Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright 2026 Hunki Enterprises BV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import json

from openupgradelib import openupgrade

from odoo.tools.translate import get_translation


def translate_section_name(env):
"""
After translations have been loaded, translate the section name for optional
products
"""
translated_section_name = {
"en_US": "Optional Products Section",
}
translated_section_name.update(
{
lang.code: get_translation(
"sale_management", lang.code, translated_section_name["en_US"], []
)
for lang in env["res.lang"].search([])
}
)
for lang, name in translated_section_name.items():
openupgrade.logged_query(
env.cr,
"""
UPDATE sale_order_line
SET name=%s
FROM sale_order, res_users, res_partner
WHERE
sale_order_line.order_id=sale_order.id
AND sale_order.create_uid=res_users.id
AND res_users.partner_id=res_partner.id
AND display_type='line_section'
AND is_optional=True
AND COALESCE(res_partner.lang, 'en_US')=%s
""",
(name, lang),
)
openupgrade.logged_query(
env.cr,
"""
UPDATE sale_order_template_line
SET name=%s
WHERE display_type='line_section' AND is_optional=True
""",
(json.dumps(translated_section_name),),
)


@openupgrade.migrate()
def migrate(env, version):
translate_section_name(env)
108 changes: 75 additions & 33 deletions openupgrade_scripts/scripts/sale_management/19.0.1.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Copyright 2026 Hunki Enterprises BV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import json

from openupgradelib import openupgrade


Expand All @@ -8,20 +10,26 @@ def sale_order_line_options(env):
Model sale.order.option has been replaced by optional lines on sale orders
"""
SaleOrderLine = env["sale.order.line"]
link_column = openupgrade.get_legacy_name("option_id")
env.cr.execute(
f"ALTER TABLE sale_order_line ADD COLUMN IF NOT EXISTS {link_column} int "
)
env.cr.execute(
"""
SELECT
id, order_id, name, product_id, quantity, price_unit, sequence, uom_id, discount
soo.order_id, name, product_id, quantity, price_unit, sequence, uom_id,
discount, line_id, max_sequence
FROM
sale_order_option
sale_order_option soo
LEFT JOIN
(
SELECT order_id, MAX(sequence) max_sequence
FROM sale_order_line
GROUP BY order_id
) order2max_sequence
ON order2max_sequence.order_id=soo.order_id
ORDER BY
order_id
"""
)
last_order_id = 0
for (
option_id,
order_id,
name,
product_id,
Expand All @@ -30,27 +38,36 @@ def sale_order_line_options(env):
sequence,
uom_id,
discount,
line_id,
max_sequence,
) in env.cr.fetchall():
line = SaleOrderLine.create(
{
"is_optional": True,
"order_id": order_id,
"name": name,
"product_id": product_id,
"product_uom_qty": quantity,
"price_unit": price_unit,
"sequence": sequence,
"product_uom_id": uom_id,
"discount": discount,
}
)
env.cr.execute(
f"""
UPDATE sale_order_line
SET {link_column}={option_id}
WHERE id={line.id}
"""
)
if order_id != last_order_id:
SaleOrderLine.create(
{
"is_optional": True,
"order_id": order_id,
"name": "/",
"display_type": "line_section",
"sequence": (max_sequence or 0) + 1,
}
)
sequence = (max_sequence or 0) + 2 + (sequence or 0)
if line_id:
SaleOrderLine.browse(line_id).sequence = sequence
else:
SaleOrderLine.create(
{
"order_id": order_id,
"name": name,
"product_id": product_id,
"product_uom_qty": quantity,
"price_unit": price_unit,
"sequence": sequence,
"product_uom_id": uom_id,
"discount": discount,
}
)
last_order_id = order_id


def sale_order_template_options(env):
Expand All @@ -66,36 +83,61 @@ def sale_order_template_options(env):
env.cr.execute(
"""
SELECT
id, sale_order_template_id, name, product_id, quantity, uom_id
id, soto.sale_order_template_id, name, product_id, quantity, uom_id,
max_sequence
FROM
sale_order_template_option
sale_order_template_option soto
LEFT JOIN
(
SELECT sale_order_template_id, max(sequence) max_sequence
FROM sale_order_template_line
GROUP BY sale_order_template_id
) template2max_sequence
ON
template2max_sequence.sale_order_template_id=soto.sale_order_template_id
ORDER BY
sale_order_template_id
"""
)
last_template_id = 0
for (
option_id,
template_id,
name,
product_id,
quantity,
uom_id,
max_sequence,
) in env.cr.fetchall():
if template_id != last_template_id:
SaleOrderTemplateLine.create(
{
"is_optional": True,
"sale_order_template_id": template_id,
"name": "/",
"display_type": "line_section",
"sequence": (max_sequence or 0) + 1,
}
)
line = SaleOrderTemplateLine.create(
{
"is_optional": True,
"sale_order_template_id": template_id,
"name": name,
"name": "/",
"product_id": product_id,
"product_uom_qty": quantity,
"product_uom_id": uom_id,
"sequence": (max_sequence or 0) + 2,
}
)
env.cr.execute(
f"""
UPDATE sale_order_template_line
SET {link_column}={option_id}
SET {link_column}={option_id}, name=%s
WHERE id={line.id}
"""
""",
(json.dumps(name),),
)
last_template_id = template_id


@openupgrade.migrate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ sale_management / sale.order.template.option / quantity (float) : D
sale_management / sale.order.template.option / sale_order_template_id (many2one): DEL relation: sale.order.template, required
sale_management / sale.order.template.option / uom_id (many2one) : DEL relation: uom.uom, required

# DONE: create optional lines / template lines from former options
# DONE: create optional lines / template lines + sections from former options

---XML records in module 'sale_management'---
DEL ir.model.access: sale_management.access_sale_order_option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,41 @@
)
order._onchange_sale_order_template_id()

order.write(
{
"order_line": [
(
0,
0,
{
"name": "non-optional line",
"product_id": env.ref("product.product_product_3").id,
"product_uom": env.ref("uom.product_uom_unit").id,
"product_uom_qty": 2,
},
)
]
}
)

order.sale_order_option_ids[0].add_option_to_order()

order.write(
{
"order_line": [
(
0,
0,
{
"name": "non-optional line2",
"product_id": env.ref("product.product_product_3").id,
"product_uom": env.ref("uom.product_uom_unit").id,
"product_uom_qty": 22,
},
)
]
}
)


env.cr.commit()
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from odoo.tests import TransactionCase
from odoo.tests import TransactionCase, tagged

from odoo.addons.openupgrade_framework import openupgrade_test

Expand All @@ -13,9 +13,48 @@ def test_sale_order_template_migration(self):
[("sale_order_template_id", "=", template.id)]
)
self.assertItemsEqual(
order.order_line.mapped("name"), ("some option", "another option")
order.order_line.mapped("name"),
(
"non-optional line",
"non-optional line2",
"/",
"some option",
"another option",
),
)
self.assertItemsEqual(order.order_line.mapped("is_optional"), (True, True))
self.assertItemsEqual(
template.sale_order_template_line_ids.mapped("is_optional"), (True, True)
order.order_line.mapped("is_optional"), (False, False, True, False, False)
)
self.assertItemsEqual(
map(lambda x: x._is_line_optional(), order.order_line),
(False, False, False, True, True),
)
self.assertItemsEqual(
template.sale_order_template_line_ids.mapped("name"),
("/", "some option", "another option"),
)
self.assertItemsEqual(
template.sale_order_template_line_ids.mapped("is_optional"),
(True, False, False),
)


@openupgrade_test
@tagged("-at_install", "post_install")
class TestSaleManagementMigrationPost(TransactionCase):
def test_sale_order_template_migration(self):
template = self.env["sale.order.template"].search(
[("name", "=", "Sale order template")],
)
self.assertItemsEqual(
template.sale_order_template_line_ids.with_context(lang="fr_FR").mapped(
"name"
),
("Section produits optionnels", "some option", "another option"),
)
self.assertItemsEqual(
template.sale_order_template_line_ids.with_context(lang="en_US").mapped(
"name"
),
("Optional Products Section", "some option", "another option"),
)
Loading