Skip to content

Commit 7882bd2

Browse files
committed
[MIG] product
1 parent 8d59a5c commit 7882bd2

File tree

7 files changed

+420
-1
lines changed

7 files changed

+420
-1
lines changed

docsource/modules180-190.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ Module coverage 18.0 -> 19.0
908908
+---------------------------------------------------+----------------------+-------------------------------------------------+
909909
| privacy_lookup | |No DB layout changes. |
910910
+---------------------------------------------------+----------------------+-------------------------------------------------+
911-
| product | | |
911+
| product | |Done |
912912
+---------------------------------------------------+----------------------+-------------------------------------------------+
913913
| product_email_template | |No DB layout changes. |
914914
+---------------------------------------------------+----------------------+-------------------------------------------------+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2025 Hunki Enterprises BV
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from openupgradelib import openupgrade
5+
6+
7+
def _product_packaging(env):
8+
"""
9+
Create UOMs corresponding to the previous packaging's qty field,
10+
reuse existing UOMs
11+
"""
12+
env.cr.execute("SELECT id, name, qty FROM product_uom")
13+
for _id, name, qty in env.cr.fetchall():
14+
product_uom = env["product.uom"].browse(_id)
15+
uom = product_uom.product_id.uom_id
16+
17+
all_uoms = uom
18+
while all_uoms.related_uom_ids - all_uoms:
19+
all_uoms += all_uoms.related_uom_ids
20+
while all_uoms.relative_uom_id - all_uoms:
21+
all_uoms += all_uoms.relative_uom_id
22+
existing_uom = env["uom.uom"]
23+
for possible_uom in all_uoms:
24+
if uom._compute_quantity(qty, possible_uom) == 1:
25+
existing_uom = possible_uom
26+
break
27+
28+
if not existing_uom:
29+
existing_uom = env["uom.uom"].create(
30+
{
31+
"name": name,
32+
"relative_uom_id": uom.id,
33+
"relative_factor": qty,
34+
}
35+
)
36+
37+
product_uom.uom_id = existing_uom
38+
39+
40+
@openupgrade.migrate()
41+
def migrate(env, version):
42+
_product_packaging(env)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Copyright 2025 Hunki Enterprises BV
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from openupgradelib import openupgrade
5+
6+
7+
def _product_product_is_favorite(env):
8+
"""
9+
Precreate product.product#is_favorite and set with sql
10+
"""
11+
openupgrade.add_columns(
12+
env, [("product.product", "is_favorite", "boolean", False, "product_product")]
13+
)
14+
env.cr.execute(
15+
"""
16+
UPDATE product_product
17+
SET is_favorite=product_template.is_favorite
18+
FROM product_template
19+
WHERE
20+
product_product.product_tmpl_id=product_template.id
21+
AND product_template.is_favorite
22+
"""
23+
)
24+
25+
26+
def _product_supplierinfo_product_tmpl_id(env):
27+
"""
28+
Precreate product.supplierinfo#{product_tmpl_id,product_uom_id} and set with sql
29+
"""
30+
openupgrade.add_columns(
31+
env,
32+
[
33+
(
34+
"product.supplierinfo",
35+
"product_tmpl_id",
36+
"many2one",
37+
None,
38+
"product_supplierinfo",
39+
),
40+
(
41+
"product.supplierinfo",
42+
"product_uom_id",
43+
"many2one",
44+
None,
45+
"product_supplierinfo",
46+
),
47+
],
48+
)
49+
env.cr.execute(
50+
"""
51+
UPDATE product_supplierinfo
52+
SET product_tmpl_id=product_product.product_tmpl_id
53+
FROM product_product
54+
WHERE
55+
product_supplierinfo.product_id=product_product.id
56+
AND product_supplierinfo.product_tmpl_id IS NULL
57+
"""
58+
)
59+
env.cr.execute(
60+
"""
61+
UPDATE product_supplierinfo
62+
SET product_uom_id=product_template.uom_id
63+
FROM product_template
64+
WHERE
65+
product_supplierinfo.product_tmpl_id=product_template.id
66+
AND product_supplierinfo.product_id IS NULL
67+
"""
68+
)
69+
env.cr.execute(
70+
"""
71+
UPDATE product_supplierinfo
72+
SET product_uom_id=product_template.uom_id
73+
FROM product_product, product_template
74+
WHERE
75+
product_supplierinfo.product_id=product_product.id
76+
AND product_product.product_tmpl_id=product_template.id
77+
AND product_supplierinfo.product_uom_id IS NULL
78+
"""
79+
)
80+
81+
82+
def _prepare_product_packaging_migration(env):
83+
"""
84+
product.packaging is replaced by UOMs being pointed at by records of product.uom
85+
Rename product_packaging here to product_uom, and amend with data in post-migration
86+
Set uom_id to dummy UOM to have the ORM set up the not null constraint correctly
87+
"""
88+
openupgrade.rename_tables(env.cr, [("product_packaging", "product_uom")])
89+
openupgrade.add_columns(
90+
env,
91+
[
92+
(
93+
"product.uom",
94+
"uom_id",
95+
"many2one",
96+
env.ref("uom.product_uom_unit").id,
97+
"product_uom",
98+
),
99+
],
100+
)
101+
102+
103+
@openupgrade.migrate()
104+
def migrate(env, version):
105+
openupgrade.delete_records_safely_by_xml_id(
106+
env,
107+
[
108+
"product.constraint_product_packaging_positive_qty",
109+
"product.product_packaging_comp_rule",
110+
],
111+
)
112+
openupgrade.rename_xmlids(
113+
env.cr,
114+
[
115+
("product.cat_expense", "product.product_category_expenses"),
116+
("product.product_category_all", "product.product_category_goods"),
117+
],
118+
)
119+
_product_product_is_favorite(env)
120+
_product_supplierinfo_product_tmpl_id(env)
121+
_prepare_product_packaging_migration(env)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---Models in module 'product'---
2+
obsolete model product.packaging
3+
new model product.uom
4+
---Fields in module 'product'---
5+
product / product.attribute / display_type (selection) : selection_keys added: [image] (most likely nothing to do)
6+
product / product.packaging / barcode (char) : DEL
7+
product / product.packaging / company_id (many2one) : DEL relation: res.company
8+
product / product.packaging / name (char) : DEL required
9+
product / product.packaging / product_id (many2one) : DEL relation: product.product, required
10+
product / product.packaging / qty (float) : DEL
11+
product / product.packaging / sequence (integer) : DEL
12+
product / product.pricelist.item / company_id (many2one) : not related anymore
13+
product / product.pricelist.item / company_id (many2one) : now a function
14+
product / product.pricelist.item / currency_id (many2one) : not related anymore
15+
product / product.pricelist.item / currency_id (many2one) : now a function
16+
product / product.product / _order : _order is now 'default_code, name, id' ('is_favorite desc, default_code, name, id')
17+
product / product.product / is_favorite (boolean) : is now stored
18+
product / product.product / is_in_selected_section_of_order (boolean): NEW
19+
product / product.product / packaging_ids (one2many) : DEL relation: product.packaging
20+
product / product.product / product_uom_ids (one2many) : NEW relation: product.uom
21+
product / product.supplierinfo / product_tmpl_id (many2one) : now required
22+
product / product.supplierinfo / product_uom_id (many2one) : NEW relation: uom.uom, required, hasdefault: compute
23+
product / product.tag / image (binary) : previously in module website_sale
24+
product / product.tag / visible_to_customers (boolean): NEW hasdefault: default
25+
product / product.template / pricelist_rule_ids (one2many) : NEW relation: product.pricelist.item
26+
product / product.template / uom_ids (many2many) : NEW relation: uom.uom
27+
product / product.template / uom_po_id (many2one) : DEL relation: uom.uom, required
28+
product / product.uom / barcode (char) : NEW required
29+
product / product.uom / company_id (many2one) : NEW relation: res.company, hasdefault: default
30+
product / product.uom / product_id (many2one) : NEW relation: product.product, required
31+
product / product.uom / uom_id (many2one) : NEW relation: uom.uom, required
32+
product / uom.uom / product_uom_ids (one2many) : NEW relation: product.uom
33+
---XML records in module 'product'---
34+
DEL decimal.precision: product.decimal_product_uom [renamed to uom module] (noupdate)
35+
DEL ir.actions.act_window: product.action_packaging_view
36+
NEW ir.actions.server: product.action_product_print_labels
37+
NEW ir.actions.server: product.action_product_template_print_labels
38+
NEW ir.model.access: product.access_product_document_manager
39+
NEW ir.model.access: product.access_product_uom_manager
40+
NEW ir.model.access: product.access_product_uom_user
41+
NEW ir.model.access: product.access_uom_uom_product_manager
42+
DEL ir.model.access: product.access_product_packaging_manager
43+
DEL ir.model.access: product.access_product_packaging_user
44+
NEW ir.model.constraint: product.constraint_product_product_combination_unique
45+
NEW ir.model.constraint: product.constraint_product_product_is_favorite_index
46+
NEW ir.model.constraint: product.constraint_product_template_is_favorite_index
47+
NEW ir.model.constraint: product.constraint_product_uom_barcode_uniq
48+
DEL ir.model.constraint: product.constraint_product_packaging_barcode_uniq
49+
DEL ir.model.constraint: product.constraint_product_packaging_positive_qty
50+
DEL ir.rule: product.product_packaging_comp_rule (noupdate)
51+
NEW ir.ui.view: product.product_pricelist_item_product_product_form_view
52+
NEW ir.ui.view: product.product_pricelist_item_product_template_form_view
53+
NEW ir.ui.view: product.product_template_list_view_purchasable
54+
NEW ir.ui.view: product.product_template_list_view_sellable
55+
NEW ir.ui.view: product.product_uom_list_view
56+
NEW ir.ui.view: product.uom_uom_form_view_inherit
57+
DEL ir.ui.view: product.product_packaging_form_view
58+
DEL ir.ui.view: product.product_packaging_form_view2
59+
DEL ir.ui.view: product.product_packaging_search_view
60+
DEL ir.ui.view: product.product_packaging_tree_view
61+
DEL ir.ui.view: product.product_packaging_tree_view2
62+
NEW product.category: product.product_category_expenses (noupdate)
63+
NEW product.category: product.product_category_goods (noupdate)
64+
NEW product.category: product.product_category_services (noupdate)
65+
DEL product.category: product.cat_expense (noupdate)
66+
DEL product.category: product.product_category_1 (noupdate)
67+
DEL product.category: product.product_category_all (noupdate)
68+
DEL res.groups: product.group_stock_packaging
69+
NEW res.groups.privilege: product.res_groups_privilege_product
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---Models in module 'product'---
2+
obsolete model product.packaging
3+
new model product.uom
4+
5+
# DONE: packagings are folded into UOMs, with product.uom linking products to the UOM that used to be a packaging
6+
7+
---Fields in module 'product'---
8+
product / product.attribute / display_type (selection) : selection_keys added: [image] (most likely nothing to do)
9+
10+
# NOTHING TO DO
11+
12+
product / product.packaging / barcode (char) : DEL
13+
product / product.packaging / company_id (many2one) : DEL relation: res.company
14+
product / product.packaging / name (char) : DEL required
15+
product / product.packaging / product_id (many2one) : DEL relation: product.product, required
16+
product / product.packaging / qty (float) : DEL
17+
product / product.packaging / sequence (integer) : DEL
18+
19+
# DONE: table is renamed to product_uom in pre-migration and matching UOMs created in post-migration
20+
21+
product / product.pricelist.item / company_id (many2one) : not related anymore
22+
product / product.pricelist.item / company_id (many2one) : now a function
23+
product / product.pricelist.item / currency_id (many2one) : not related anymore
24+
product / product.pricelist.item / currency_id (many2one) : now a function
25+
26+
# NOTHING TO DO: related field was stored before
27+
28+
product / product.product / _order : _order is now 'default_code, name, id' ('is_favorite desc, default_code, name, id')
29+
30+
# NOTHING TO DO
31+
32+
product / product.product / is_favorite (boolean) : is now stored
33+
34+
# DONE: pre-created in pre-migration and filled from product_template
35+
36+
product / product.product / is_in_selected_section_of_order (boolean): NEW
37+
38+
# NOTHING TO DO: virtual field only used for searching
39+
40+
product / product.product / packaging_ids (one2many) : DEL relation: product.packaging
41+
product / product.product / product_uom_ids (one2many) : NEW relation: product.uom
42+
43+
# DONE: see above at product.packaging
44+
45+
product / product.supplierinfo / product_tmpl_id (many2one) : now required
46+
product / product.supplierinfo / product_uom_id (many2one) : NEW relation: uom.uom, required, hasdefault: compute
47+
48+
# DONE: filled from product_id
49+
50+
product / product.tag / image (binary) : previously in module website_sale
51+
52+
# NOTHING TO DO
53+
54+
product / product.tag / visible_to_customers (boolean): NEW hasdefault: default
55+
56+
# NOTHING TO DO
57+
58+
product / product.template / pricelist_rule_ids (one2many) : NEW relation: product.pricelist.item
59+
60+
# NOTHING TO DO
61+
62+
product / product.template / uom_ids (many2many) : NEW relation: uom.uom
63+
product / product.template / uom_po_id (many2one) : DEL relation: uom.uom, required
64+
65+
# NOTHING TO DO
66+
67+
product / product.uom / barcode (char) : NEW required
68+
product / product.uom / company_id (many2one) : NEW relation: res.company, hasdefault: default
69+
product / product.uom / product_id (many2one) : NEW relation: product.product, required
70+
product / product.uom / uom_id (many2one) : NEW relation: uom.uom, required
71+
product / uom.uom / product_uom_ids (one2many) : NEW relation: product.uom
72+
73+
# DONE: see above at product.packaging
74+
75+
---XML records in module 'product'---
76+
DEL decimal.precision: product.decimal_product_uom [renamed to uom module] (noupdate)
77+
78+
# DONE: in uom migration
79+
80+
DEL ir.actions.act_window: product.action_packaging_view
81+
NEW ir.actions.server: product.action_product_print_labels
82+
NEW ir.actions.server: product.action_product_template_print_labels
83+
NEW ir.model.access: product.access_product_document_manager
84+
NEW ir.model.access: product.access_product_uom_manager
85+
NEW ir.model.access: product.access_product_uom_user
86+
NEW ir.model.access: product.access_uom_uom_product_manager
87+
DEL ir.model.access: product.access_product_packaging_manager
88+
DEL ir.model.access: product.access_product_packaging_user
89+
90+
# NOTHING TO DO
91+
92+
NEW ir.model.constraint: product.constraint_product_product_combination_unique
93+
NEW ir.model.constraint: product.constraint_product_product_is_favorite_index
94+
NEW ir.model.constraint: product.constraint_product_template_is_favorite_index
95+
NEW ir.model.constraint: product.constraint_product_uom_barcode_uniq
96+
DEL ir.model.constraint: product.constraint_product_packaging_barcode_uniq
97+
98+
# NOTHING TO DO
99+
100+
DEL ir.model.constraint: product.constraint_product_packaging_positive_qty
101+
DEL ir.rule: product.product_packaging_comp_rule (noupdate)
102+
103+
# DONE: deleted in pre-migration
104+
105+
NEW ir.ui.view: product.product_pricelist_item_product_product_form_view
106+
NEW ir.ui.view: product.product_pricelist_item_product_template_form_view
107+
NEW ir.ui.view: product.product_template_list_view_purchasable
108+
NEW ir.ui.view: product.product_template_list_view_sellable
109+
NEW ir.ui.view: product.product_uom_list_view
110+
NEW ir.ui.view: product.uom_uom_form_view_inherit
111+
DEL ir.ui.view: product.product_packaging_form_view
112+
DEL ir.ui.view: product.product_packaging_form_view2
113+
DEL ir.ui.view: product.product_packaging_search_view
114+
DEL ir.ui.view: product.product_packaging_tree_view
115+
DEL ir.ui.view: product.product_packaging_tree_view2
116+
117+
# NOTHING TO DO
118+
119+
NEW product.category: product.product_category_expenses (noupdate)
120+
NEW product.category: product.product_category_goods (noupdate)
121+
NEW product.category: product.product_category_services (noupdate)
122+
DEL product.category: product.cat_expense (noupdate)
123+
DEL product.category: product.product_category_1 (noupdate)
124+
DEL product.category: product.product_category_all (noupdate)
125+
126+
# DONE: renamed in pre-migration
127+
128+
DEL res.groups: product.group_stock_packaging
129+
NEW res.groups.privilege: product.res_groups_privilege_product
130+
131+
# NOTHING TO DO

0 commit comments

Comments
 (0)