-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MIG] sale_order_rename: Migration to 16.0
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
1 parent
51137ef
commit 4458c3c
Showing
4 changed files
with
130 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,39 @@ | ||
# 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!" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,117 @@ | ||
# 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.tests import common | ||
from odoo.tools.misc import mute_logger | ||
|
||
_ir_sequence_class = 'odoo.addons.base.models.ir_sequence.IrSequence' | ||
from odoo.tests import common, tagged | ||
from odoo.exceptions import UserError | ||
|
||
|
||
@tagged("post_install", "-at_install", "sale_order_rename") | ||
class TestSaleOrderRename(common.TransactionCase): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
|
||
self.SaleOrder = self.env['sale.order'] | ||
self.SudoSaleOrder = self.SaleOrder.sudo() | ||
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 test_1(self): | ||
self.SudoSaleOrder.create({ | ||
'name': 'Test #1', | ||
'partner_id': self.env.ref('base.res_partner_1').id, | ||
}) | ||
def _create_company(self): | ||
return self.env["res.company"].create( | ||
{ | ||
"name": "Test Company", | ||
} | ||
) | ||
|
||
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, | ||
}) | ||
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, | ||
} | ||
]) | ||
|
||
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, | ||
}) | ||
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, | ||
} | ||
]) | ||
|
||
|
||
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, | ||
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", | ||
}) | ||
|
||
self.assertNotEqual(sale_order_1.name, sale_order_2.name) | ||
|
||
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", | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters