Initial commit: Core packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:45 +02:00
commit 12c29a983b
9512 changed files with 8379910 additions and 0 deletions

View file

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_routes
from . import test_utm
from . import test_utm_consistency
from . import test_utm_security

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import common
from odoo.tests.common import tagged
class TestUTMCommon(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestUTMCommon, cls).setUpClass()
cls.utm_campaign = cls.env['utm.campaign'].create({'name': 'Test Campaign'})
cls.utm_medium = cls.env['utm.medium'].create({'name': 'Test Medium'})
cls.utm_source = cls.env['utm.source'].create({'name': 'Test Source'})
cls.user_employee = cls.env['res.users'].create({
'name': 'User Employee',
'login': 'user_employee_utm',
'email': 'user_employee_utm@test.com',
'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])],
})

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
@odoo.tests.tagged('post_install', '-at_install')
class TestRoutes(HttpCaseWithUserDemo):
def test_01_web_session_destroy(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
self.authenticate('demo', 'demo')
res = self.opener.post(url=base_url + '/web/session/destroy', json={})
self.assertEqual(res.status_code, 200)

View file

@ -0,0 +1,171 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.utm.models.utm_mixin import UtmMixin
from odoo.addons.utm.tests.common import TestUTMCommon
from odoo.tests import tagged
@tagged("utm", "post_install", "-at_install")
class TestUtm(TestUTMCommon):
def test_campaign_automatic_name(self):
""" Test automatic naming of campaigns based on title """
campaigns = self.env["utm.campaign"].create([
{"title": "Title"},
{"name": "ForcedName", "title": "WithTitle"}
])
self.assertEqual(campaigns[0].name, "Title")
self.assertEqual(campaigns[1].name, "ForcedName")
campaigns[0].title = "ForcedName"
self.assertEqual(campaigns[0].name, "ForcedName [2]")
self.assertEqual(campaigns[0].name, "ForcedName [2]")
def test_find_or_create_record(self):
""" Tests for '_find_or_create_record' """
source_1, source_2 = self.env['utm.source'].create([{
'name': 'Source 1',
}, {
'name': 'Source 2',
}])
# Find the record based on the given name
source = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 1')
self.assertEqual(source, source_1)
source = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 2')
self.assertEqual(source, source_2)
# Create a new record
source_3 = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 3')
self.assertNotIn(source_3, source_1 | source_2)
self.assertEqual(source_3.name, 'Source 3')
# Duplicate mark: valid new record
source_3_2 = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 3 [2]')
self.assertNotIn(source_3_2, source_1 | source_2 | source_3)
self.assertEqual(source_3_2.name, 'Source 3 [2]')
# New source with duplicate mark ...
source_4_2 = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 4 [2]')
self.assertNotIn(source_4_2, source_1 | source_2 | source_3 | source_3_2)
self.assertEqual(source_4_2.name, 'Source 4 [2]')
source_4_2_bis = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 4 [2]')
self.assertEqual(source_4_2_bis, source_4_2)
# ... then basic without duplicate mark
source_4 = self.env['utm.mixin']._find_or_create_record('utm.source', 'Source 4')
self.assertNotIn(source_4, source_1 | source_2 | source_3 | source_3_2 | source_4_2)
self.assertEqual(source_4.name, 'Source 4')
def test_name_generation(self):
"""Test that the name is always unique. A counter must be added at the
end of the name if it's not the case."""
for utm_model in ('utm.source', 'utm.medium', 'utm.campaign'):
utm_0 = self.env[utm_model].create({'name': 'UTM new'})
utm_1, utm_2, utm_3, utm_4, utm_5 = self.env[utm_model].create([
{
'name': 'UTM 1',
}, {
'name': 'UTM 2',
}, {
# UTM record 3 has the same name of the previous UTM record
'name': 'UTM new',
}, {
# UTM record 4 has the same name of the previous UTM record
'name': 'UTM new',
}, {
# UTM record 5 has the same name of the previous UTM record
# but with a wrong counter part, it should be removed and updated
'name': 'UTM new [0]',
},
])
self.assertEqual(utm_0.name, 'UTM new', msg='The first "UTM dup" should be left unchanged since it is unique')
self.assertEqual(utm_1.name, 'UTM 1', msg='This name is already unique')
self.assertEqual(utm_2.name, 'UTM 2', msg='This name is already unique')
self.assertEqual(utm_3.name, 'UTM new [2]', msg='Must add a counter as suffix to ensure uniqueness')
self.assertEqual(utm_4.name, 'UTM new [3]', msg='Must add a counter as suffix to ensure uniqueness')
self.assertEqual(utm_5.name, 'UTM new [4]', msg='Must add a counter as suffix to ensure uniqueness')
(utm_0 | utm_3 | utm_4).unlink()
utm_new_multi = self.env[utm_model].create([{'name': 'UTM new'} for _ in range(4)])
self.assertListEqual(
utm_new_multi.mapped('name'),
['UTM new', 'UTM new [2]', 'UTM new [3]', 'UTM new [5]'],
'Duplicate counters should be filled in order of missing.')
# no ilike-based duplicate
utm_7 = self.env[utm_model].create({'name': 'UTM ne'})
self.assertEqual(
utm_7.name, 'UTM ne',
msg='Even if this name has the same prefix as the other, it is still unique')
# copy should avoid uniqueness issues
utm_8 = utm_7.copy()
self.assertEqual(
utm_8.name, 'UTM ne [2]',
msg='Must add a counter as suffix to ensure uniqueness')
# Test name uniqueness when creating a campaign using a title (quick creation)
utm_9 = self.env['utm.campaign'].create({'title': 'UTM ne'})
self.assertEqual(
utm_9.name, 'UTM ne [3]',
msg='Even if the record has been created using a title, the name must be unique')
def test_name_generation_duplicate_marks(self):
""" Check corner cases when giving duplicate marks directly in name """
for utm_model in ('utm.source', 'utm.medium', 'utm.campaign'):
utm = self.env[utm_model].create({"name": "MarkTest [2]"})
self.assertEqual(
utm.name, "MarkTest [2]",
"Should respect creation value")
utm.write({"name": "MarkTest [2]"})
self.assertEqual(
utm.name, "MarkTest [2]",
"Writing same value: should not auto increment")
utm.write({"name": "MarkTest"})
self.assertEqual(
utm.name, "MarkTest",
"First available counter")
utm.write({"name": "MarkTest [8]"})
self.assertEqual(
utm.name, "MarkTest [8]",
"Should respect given values")
utm_batch = self.env[utm_model].create([
{"name": "BatchTest [2]"}
for x in range(4)
])
self.assertEqual(
utm_batch.mapped("name"),
["BatchTest [2]", "BatchTest", "BatchTest [3]", "BatchTest [4]"],
"Accept input if possible, otherwise increment"
)
utm_batch_nodup = self.env[utm_model].create([
{"name": "NoDupBatch [2]"},
{"name": "NoDupBatch [4]"},
{"name": "NoDupBatch [6]"},
{"name": "Margoulin"},
])
self.assertEqual(
utm_batch_nodup.mapped("name"),
["NoDupBatch [2]", "NoDupBatch [4]", "NoDupBatch [6]", "Margoulin"]
)
def test_split_name_and_count(self):
""" Test for tool '_split_name_and_count' """
for name, (expected_name, expected_count) in [
("medium", ("medium", 1)),
("medium [0]", ("medium", 0)),
("medium [1]", ("medium", 1)),
("medium [x]", ("medium [x]", 1)), # not integer -> do not care
("medium [0", ("medium [0", 1)), # unrecognized -> do not crash
]:
with self.subTest(name=name):
self.assertEqual(UtmMixin._split_name_and_count(name), (expected_name, expected_count))

View file

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.utm.tests.common import TestUTMCommon
from odoo.exceptions import UserError
from odoo.tests.common import tagged, users
@tagged('post_install', '-at_install', 'utm', 'utm_consistency')
class TestUTMConsistency(TestUTMCommon):
@users('__system__')
def test_utm_consistency(self):
""" You are not supposed to delete the 'utm_medium_email' record as it is hardcoded in
some functional flows, notably in HR and Mass Mailing. """
with self.assertRaises(UserError):
self.env.ref('utm.utm_medium_email').unlink()

View file

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.utm.tests.common import TestUTMCommon
from odoo.exceptions import AccessError
from odoo.tests.common import tagged, users
@tagged('post_install', '-at_install', 'security', 'utm')
class TestUTMSecurity(TestUTMCommon):
@users('__system__')
def test_utm_security_admin(self):
""" base.group_system members can do anything on main UTM models. """
UtmCampaign = self.env['utm.campaign']
UtmMedium = self.env['utm.medium']
UtmSource = self.env['utm.source']
# CREATE
test_utm_campaign = UtmCampaign.create({'name': 'Campaign ACLs'})
test_utm_medium = UtmMedium.create({'name': 'Medium ACLs'})
test_utm_source = UtmSource.create({'name': 'Source ACLs'})
# READ
self.assertEqual(
UtmCampaign.search([('id', '=', test_utm_campaign.id)]),
test_utm_campaign)
self.assertEqual(
UtmMedium.search([('id', '=', test_utm_medium.id)]),
test_utm_medium)
self.assertEqual(
UtmSource.search([('id', '=', test_utm_source.id)]),
test_utm_source)
# UPDATE
test_utm_campaign.write({'name': 'Campaign EDITED'})
test_utm_medium.write({'name': 'Medium EDITED'})
test_utm_source.write({'name': 'Source EDITED'})
# UNLINK
test_utm_campaign.unlink()
test_utm_medium.unlink()
test_utm_source.unlink()
@users('user_employee_utm')
def test_utm_security_employee(self):
""" base.group_user members can do anything on main UTM models BUT unlink. """
UtmCampaign = self.env['utm.campaign']
UtmMedium = self.env['utm.medium']
UtmSource = self.env['utm.source']
# CREATE
test_utm_campaign = UtmCampaign.create({'name': 'Campaign ACLs'})
test_utm_medium = UtmMedium.create({'name': 'Medium ACLs'})
test_utm_source = UtmSource.create({'name': 'Source ACLs'})
# READ
self.assertEqual(
UtmCampaign.search([('id', '=', test_utm_campaign.id)]),
test_utm_campaign)
self.assertEqual(
UtmMedium.search([('id', '=', test_utm_medium.id)]),
test_utm_medium)
self.assertEqual(
UtmSource.search([('id', '=', test_utm_source.id)]),
test_utm_source)
# UPDATE
test_utm_campaign.write({'name': 'Campaign EDITED'})
test_utm_medium.write({'name': 'Medium EDITED'})
test_utm_source.write({'name': 'Source EDITED'})
# UNLINK
with self.assertRaises(AccessError):
test_utm_campaign.unlink()
with self.assertRaises(AccessError):
test_utm_medium.unlink()
with self.assertRaises(AccessError):
test_utm_source.unlink()