Skip to content

Commit

Permalink
[MIG] sale_order_rename: Migration to 16.0
Browse files Browse the repository at this point in the history
Rewrite check for unique sale.order name, using api.constraint and ensure that name is unique on same company.
Update test according to new name uniqueness check logic
Remove xpath for sale order name label because the form is always in edit mode
  • Loading branch information
patrickt-oforce committed Jan 30, 2025
1 parent 51137ef commit 7031632
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 90 deletions.
2 changes: 1 addition & 1 deletion sale_order_rename/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{
"name": "Sale Order Rename",
"version": "12.0.1.0.2",
"version": "16.0.1.0.0",
"category": "Sales",
"website": "https://github.com/OCA/sale-workflow",
"author": "CorporateHub, " "Odoo Community Association (OCA)",
Expand Down
21 changes: 9 additions & 12 deletions sale_order_rename/i18n/sale_order_rename.pot
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_rename
# * sale_order_rename
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Project-Id-Version: Odoo Server 16.0+e-20250113\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"POT-Creation-Date: 2025-01-30 11:19+0000\n"
"PO-Revision-Date: 2025-01-30 11:19+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: sale_order_rename
#: code:addons/sale_order_rename/models/sale_order.py:26
#. odoo-python
#: code:addons/sale_order_rename/models/sale_order.py:0
#, python-format
msgid "New"
msgid "Sale Order name must be unique within a company!"
msgstr ""

#. module: sale_order_rename
#: model:ir.model,name:sale_order_rename.model_sale_order
msgid "Sale Order"
msgstr ""

#. module: sale_order_rename
#: sql_constraint:sale.order:0
msgid "Sale Order name must be unique within a company!"
msgid "Sales Order"
msgstr ""

48 changes: 22 additions & 26 deletions sale_order_rename/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
# Copyright 2018 Brainbean Apps (https://brainbeanapps.com)
# Copyright 2025 Openforce Srls Unipersonale (www.openforce.it)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
from psycopg2 import IntegrityError

from odoo import models, api, _, tools
from odoo import _, api, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class SaleOrder(models.Model):
_inherit = 'sale.order'
_inherit = "sale.order"

_name_company_uniq_constraint = 'name_company_uniq'
_sql_constraints = [
(
_name_company_uniq_constraint,
'unique(name, company_id)',
'Sale Order name must be unique within a company!'
),
]

@api.model
def create(self, vals):
is_name_generated = vals.get('name', _('New')) != _('New')
duplicate_key_msg = 'duplicate key value violates unique constraint'
while True:
try:
with self._cr.savepoint(), tools.mute_logger('odoo.sql_db'):
return super().create(vals.copy())
except IntegrityError as e:
e_msg = str(e)
if is_name_generated or duplicate_key_msg not in e_msg or \
self._name_company_uniq_constraint not in e_msg:
raise e
_logger.debug('Duplicate sale.order name, retrying creation')
@api.constrains("name")
def _check_unique_name_in_company(self):
so_obj = self.env["sale.order"]
for so in self:
domain = [
("name", "=", so.name),
("company_id", "=", so.company_id.id),
("id", "!=", so.id),
]
if so_obj.search_count(domain):
_logger.error(
"Sale Order name %(so_name)s exists for company:" " %(company)s",
{
"so_name": so.name,
"company": so.company_id.name,
},
)
raise UserError(_("Sale Order name must be unique within a company!"))
165 changes: 119 additions & 46 deletions sale_order_rename/tests/test_sale_order_rename.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,129 @@
# Copyright 2018 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from psycopg2 import IntegrityError
from unittest import mock

from odoo.exceptions import UserError
from odoo.tests import common
from odoo.tools.misc import mute_logger

_ir_sequence_class = 'odoo.addons.base.models.ir_sequence.IrSequence'


class TestSaleOrderRename(common.TransactionCase):

def setUp(self):
super().setUp()

self.SaleOrder = self.env['sale.order']
self.SudoSaleOrder = self.SaleOrder.sudo()

def test_1(self):
self.SudoSaleOrder.create({
'name': 'Test #1',
'partner_id': self.env.ref('base.res_partner_1').id,
})

with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
self.SudoSaleOrder.create({
'name': 'Test #1',
'partner_id': self.env.ref('base.res_partner_1').id,
})

def test_2(self):
sale_order_1 = self.SudoSaleOrder.create({
'partner_id': self.env.ref('base.res_partner_1').id,
})
sale_order_2 = self.SudoSaleOrder.create({
'partner_id': self.env.ref('base.res_partner_1').id,
})

self.assertNotEqual(sale_order_1.name, sale_order_2.name)

def test_3(self):
sale_order_1 = self.SudoSaleOrder.create({
'name': 'Test #3-1',
'partner_id': self.env.ref('base.res_partner_1').id,
})

with mock.patch(
_ir_sequence_class + '.next_by_code',
side_effect=['Test #3-1', 'Test #3-2']):
sale_order_2 = self.SudoSaleOrder.create({
'partner_id': self.env.ref('base.res_partner_1').id,
})

self.assertNotEqual(sale_order_1.name, sale_order_2.name)
self.sale_order = self.env["sale.order"]
self.sale_order_sudo = self.sale_order.sudo()
self.base_company = self.env.ref("base.main_company")
self.other_company = self._create_company()

def _create_company(self):
return self.env["res.company"].create(
{
"name": "Test Company",
}
)

def test_01_two_sale_order_with_same_name_in_different_companies(self):
so_vals = {
"name": "Test #1",
"partner_id": self.env.ref("base.res_partner_1").id,
}
self.sale_order.create(
[
{
**so_vals,
"company_id": self.base_company.id,
}
]
)
self.sale_order.create(
[
{
**so_vals,
"company_id": self.other_company.id,
}
]
)

def test_02_raise_exception_two_sale_order_with_same_name_in_same_company(self):
so_vals = {
"name": "Test #1",
"partner_id": self.env.ref("base.res_partner_1").id,
}
self.sale_order.create(
[
{
**so_vals,
"company_id": self.base_company.id,
}
]
)
with self.assertRaises(UserError):
self.sale_order.create(
[
{
**so_vals,
"company_id": self.base_company.id,
}
]
)

def test_03_raise_exception_renaming_two_so_in_same_company_with_same_name(self):
so_vals = {
"company_id": self.base_company.id,
"partner_id": self.env.ref("base.res_partner_1").id,
}
so1 = self.sale_order.create(
[
{
**so_vals,
}
]
)
so2 = self.sale_order.create(
[
{
**so_vals,
}
]
)
so1.write(
{
"name": "Test #1",
}
)
with self.assertRaises(UserError):
so2.write(
{
"name": "Test #1",
}
)

def test_04_allowed_renaming_two_so_in_different_company_with_same_name(self):
so_vals = {
"partner_id": self.env.ref("base.res_partner_1").id,
}
so1 = self.sale_order.create(
[
{
**so_vals,
"company_id": self.base_company.id,
}
]
)
so2 = self.sale_order.create(
[
{
**so_vals,
"company_id": self.other_company.id,
}
]
)
so1.write(
{
"name": "Test #1",
}
)
so2.write(
{
"name": "Test #1",
}
)
9 changes: 4 additions & 5 deletions sale_order_rename/views/sale_order.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
<record id="sale_order_form_view" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="readonly">0</attribute>
<attribute name="attrs">{'readonly': [('state', 'not in', ['draft'])]}</attribute>
</xpath>
<xpath expr="//field[@name='name']/.." position="before">
<label for="name" class="oe_edit_only" attrs="{'invisible': [('state', 'in', ['draft'])]}"/>
<attribute
name="attrs"
>{'readonly': [('state', 'not in', ['draft'])]}</attribute>
</xpath>
</field>
</record>
Expand Down

0 comments on commit 7031632

Please sign in to comment.