chore: import enterprise addons 19.0 bulk snapshot

This commit is contained in:
1b-agent committed 2026-09-16 10:13:08 +00:00
commit ca4af030d3
39951 files changed
+15570005

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+1
View File
@@ -0,0 +1 @@
{'name': 'Social Tests (Full)', 'version': '1.0', 'category': 'Hidden', 'sequence': 9878, 'summary': 'Social Tests: tests specific to social with all sub-modules', 'description': 'This module contains tests related to various social features\nand social-related sub modules. It will test interactions between all those modules.', 'depends': [], 'installable': True, 'author': 'Odoo S.A.', 'license': 'LGPL-3', 'assets': {'web.assets_unit_tests': ['social_test_full/static/tests/**/*']}}
@@ -0,0 +1,149 @@
import { expect, test } from "@odoo/hoot";
import { markup } from "@odoo/owl";
import { patchWithCleanup } from "@web/../tests/web_test_helpers";
import { SocialPostFormatterMixinBase } from "@social/js/social_post_formatter_mixin";
const Markup = markup("").constructor;
test("Facebook Message", () => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() {
return "facebook";
},
_formatPost() {
this.originalPost = { account_id: { raw_value: 42 } };
return super._formatPost(...arguments);
},
});
const testMessage =
"Hello @[542132] Odoo-Social, check this out: https://www.odoo.com?utm=mail&param=1,2,3 #crazydeals #odoo";
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
expect(finalMessage.toString()).toEqual(
[
"Hello",
"<a href='/social_facebook/redirect_to_profile/42/542132?name=Odoo-Social' target='_blank'>Odoo-Social</a>,",
"check this out:",
"<a href='https://www.odoo.com?utm=mail&amp;param=1,2,3' class='text-truncate' target='_blank' rel='noreferrer noopener'>https://www.odoo.com?utm=mail&amp;param=1,2,3</a>",
"<a href='https://www.facebook.com/hashtag/crazydeals' target='_blank'>#crazydeals</a>",
"<a href='https://www.facebook.com/hashtag/odoo' target='_blank'>#odoo</a>",
].join(" ")
);
expect(finalMessage).toBeInstanceOf(Markup);
});
test("Instagram Message", () => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() {
return "instagram";
},
});
const testMessage =
"Hello @Odoo.Social, check this out: https://www.odoo.com #crazydeals #odoo";
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
expect(finalMessage.toString()).toEqual(
[
"Hello",
"<a href='https://www.instagram.com/Odoo.Social' target='_blank'>@Odoo.Social</a>,",
"check this out:",
"<a href='https://www.odoo.com' class='text-truncate' target='_blank' rel='noreferrer noopener'>https://www.odoo.com</a>",
"<a href='https://www.instagram.com/explore/tags/crazydeals' target='_blank'>#crazydeals</a>",
"<a href='https://www.instagram.com/explore/tags/odoo' target='_blank'>#odoo</a>",
].join(" ")
);
expect(finalMessage).toBeInstanceOf(Markup);
});
test("LinkedIn Message", () => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() {
return "linkedin";
},
});
const testMessage = "Hello, check this out: https://www.odoo.com {hashtag|#|crazydeals} #odoo";
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
expect(finalMessage.toString()).toEqual(
[
"Hello, check this out:",
"<a href='https://www.odoo.com' class='text-truncate' target='_blank' rel='noreferrer noopener'>https://www.odoo.com</a>",
"<a href='https://www.linkedin.com/feed/hashtag/?keywords=crazydeals' target='_blank'>#crazydeals</a>",
"<a href='https://www.linkedin.com/feed/hashtag/?keywords=odoo' target='_blank'>#odoo</a>",
].join(" ")
);
expect(finalMessage).toBeInstanceOf(Markup);
});
test("Twitter Message", () => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() {
return "twitter";
},
});
const testMessage =
"Hello @Odoo-Social, check this out: https://www.odoo.com #crazydeals #odoo";
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
expect(finalMessage.toString()).toEqual(
[
"Hello",
"<a href='https://twitter.com/Odoo-Social' target='_blank'>@Odoo-Social</a>,",
"check this out:",
"<a href='https://www.odoo.com' class='text-truncate' target='_blank' rel='noreferrer noopener'>https://www.odoo.com</a>",
"<a href='https://twitter.com/hashtag/crazydeals?src=hash' target='_blank'>#crazydeals</a>",
"<a href='https://twitter.com/hashtag/odoo?src=hash' target='_blank'>#odoo</a>",
].join(" ")
);
expect(finalMessage).toBeInstanceOf(Markup);
});
test("YouTube Message", () => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() {
return "youtube";
},
});
const testMessage = "Hello, check this out: https://www.odoo.com #crazydeals #odoo";
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
expect(finalMessage.toString()).toEqual(
[
"Hello, check this out:",
"<a href='https://www.odoo.com' class='text-truncate' target='_blank' rel='noreferrer noopener'>https://www.odoo.com</a>",
"<a href='https://www.youtube.com/results?search_query=%23crazydeals' target='_blank'>#crazydeals</a>",
"<a href='https://www.youtube.com/results?search_query=%23odoo' target='_blank'>#odoo</a>",
].join(" ")
);
expect(finalMessage).toBeInstanceOf(Markup);
});
test("URL regex supports special characters across all media types", () => {
const mediaTypes = ['facebook', 'instagram', 'linkedin', 'twitter', 'youtube'];
const testUrl = 'https://example.com/path(v1)/search?tags=$web,mobile*&price=$100';
const testMessage = `Check this URL: ${testUrl} #test`;
const testUrlNoAnd = testUrl.replace(/&/g, '&amp;');
expect.assertions(mediaTypes.length);
mediaTypes.forEach(mediaType => {
patchWithCleanup(SocialPostFormatterMixinBase, {
_getMediaType() { return mediaType; },
});
const finalMessage = SocialPostFormatterMixinBase._formatPost(testMessage);
const expectedUrlPattern = `<a href='${testUrlNoAnd}' class='text-truncate' target='_blank' rel='noreferrer noopener'>${testUrlNoAnd}</a>`;
expect(finalMessage.includes(expectedUrlPattern)).toBe(
true,
{ message: `URL with special characters (parentheses, asterisk, dollar sign, comma, apostrophe) should be properly formatted for ${mediaType}` }
);
});
});
@@ -0,0 +1,85 @@
import { expect, test } from "@odoo/hoot";
import { queryOne } from "@odoo/hoot-dom";
import { defineModels, models, mountView } from "@web/../tests/web_test_helpers";
import { defineMailModels } from "@mail/../tests/mail_test_helpers";
class SocialPostTemplate extends models.ServerModel {
_name = "social.post.template";
_records = [
{
id: 1,
message: "Hello @Odoo-Social, check this out: https://www.odoo.com #crazydeals #odoo",
twitter_message:
"Hello @Odoo-Social, check this out: https://www.odoo.com #crazydeals #odoo",
is_split_per_media: false,
has_twitter_account: true,
twitter_preview: `
<div class="o_social_preview o_social_twitter_preview bg-white border rounded overflow-hidden w-100">
<div class="w-75 d-flex m-3">
<span class="o_social_preview_icon_wrapper overflow-hidden me-2">
<i class="fa fa-twitter fa-2x"></i>
</span>
<div class="o_social_preview_header">
<b class="text-900">X Account</b>
<span class="text-600">@x ·
11m
</span>
</div>
</div>
<div class="d-table w-75 pb-3 mx-3">
<span class="o_social_preview_message">Hello <a href="https://twitter.com/Odoo-Social" target="_blank" rel="noreferrer">@Odoo-Social</a>, check this out: <a href="https://www.odoo.com" class="text-truncate" target="_blank" rel="noreferrer">https://www.odoo.com</a> <a href="https://twitter.com/hashtag/crazydeals?src=hash" target="_blank" rel="noreferrer">#crazydeals</a> <a href="https://twitter.com/hashtag/odoo?src=hash" target="_blank" rel="noreferrer">#odoo</a></span>
</div>
<a target="_blank" href="https://www.odoo.com" rel="noreferrer">
<div class="o_social_stream_post_image d-flex overflow-hidden o_social_stream_post_image_clickable">
<div class="w-100">
<img alt="Post Image" src="https://www.odoo.com/web/image/54404732-3d9bec26/SPI_homepage.png">
</div>
</div>
<div class="o_social_twitter_preview_article w-100 pb-1 d-block text-white">
<small class="p-1 mx-2 rounded">www.odoo.com</small>
</div>
</a>
</div>`,
},
];
_views = {
form: `
<form string="Social Post Template" class="o_social_post_view_form">
<sheet>
<group>
<group string="Your Post" name="social_post_global" class="o_social_post_form_content">
<field name="is_split_per_media" invisible="1"/>
<field name="twitter_message" invisible="1"/>
<field name="twitter_preview" widget="social_post_preview" media_type="twitter" readonly="1"/>
</group>
</group>
</sheet>
</form>
`,
};
}
defineMailModels();
defineModels([SocialPostTemplate]);
test("SocialPostFormatterMixin on HtmlField is working as expected", async () => {
await mountView({
type: "form",
resId: 1,
resModel: "social.post.template",
});
const htmlValue = queryOne(".o_social_preview_message").innerHTML;
expect(htmlValue).toEqual(
[
`Hello`,
`<a href="https://twitter.com/Odoo-Social" target="_blank">@Odoo-Social</a>,`,
`check this out:`,
`<a href="https://www.odoo.com" class="text-truncate" target="_blank" rel="noreferrer noopener">https://www.odoo.com</a>`,
`<a href="https://twitter.com/hashtag/crazydeals?src=hash" target="_blank">#crazydeals</a>`,
`<a href="https://twitter.com/hashtag/odoo?src=hash" target="_blank">#odoo</a>`,
].join(" ")
);
});
+7
View File
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_social_basic
from . import test_social_crm_convert
from . import test_social_youtube
+26
View File
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.social.tests.tools import mock_void_external_calls
from odoo.tests import common
class SocialTestFullCase(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(SocialTestFullCase, cls).setUpClass()
media_refs = [
'social_instagram.social_media_instagram',
'social_facebook.social_media_facebook',
'social_twitter.social_media_twitter',
'social_linkedin.social_media_linkedin',
'social_push_notifications.social_media_push_notifications',
'social_youtube.social_media_youtube',
]
with mock_void_external_calls():
# create one account for every media type
cls.accounts = cls.env['social.account'].create([{
'media_id': cls.env.ref(media_ref).id,
'name': 'Account'
} for media_ref in media_refs])
@@ -0,0 +1,78 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from freezegun import freeze_time
from unittest.mock import patch
from odoo.sql_db import Cursor
from odoo.addons.social_test_full.tests.common import SocialTestFullCase
class TestSocialBasic(SocialTestFullCase):
def test_split_per_media(self):
images = self.env["ir.attachment"].create(
[{"name": "img.jpg"} for _ in range(3)]
)
post = self.env["social.post"].create(
{
# Facebook - Twitter - Push Notification
"account_ids": (self.accounts[1:3] + self.accounts[4]).ids,
"image_ids": images[0].ids,
"message": "test",
}
)
self.assertEqual(post.facebook_message, "test")
self.assertEqual(post.twitter_message, "test")
self.assertEqual(post.push_notification_message, "test")
self.assertEqual(post.facebook_image_ids, images[0])
self.assertEqual(post.twitter_image_ids, images[0])
post.message = "test 2"
post.image_ids = images.ids
self.assertEqual(post.facebook_message, "test 2")
self.assertEqual(post.twitter_message, "test 2")
self.assertEqual(post.push_notification_message, "test 2")
self.assertEqual(post.facebook_image_ids, images)
self.assertEqual(post.twitter_image_ids, images)
post.is_split_per_media = True
post.facebook_message = "test fb"
post.twitter_image_ids = images[1].ids
self.assertEqual(post.facebook_message, "test fb")
self.assertEqual(post.twitter_message, "test 2")
self.assertEqual(post.push_notification_message, "test 2")
self.assertEqual(post.facebook_image_ids, images)
self.assertEqual(post.twitter_image_ids, images[1])
post.action_post()
self.assertEqual(post.live_post_ids[0].message, "test fb")
self.assertEqual(post.live_post_ids[0].image_ids, images)
self.assertEqual(post.live_post_ids[1].message, "test 2")
self.assertEqual(post.live_post_ids[1].image_ids, images[1])
self.assertEqual(post.live_post_ids[2].message, "test 2")
self.assertFalse(post.live_post_ids[2].image_ids)
@freeze_time("2022-01-02")
@patch.object(Cursor, "now", lambda *args, **kwargs: datetime(2022, 1, 2))
def test_utm_source_name(self):
post_1, post_2 = self.env["social.post"].create(
[
{
"account_ids": [(4, self.accounts[2].id)],
"is_split_per_media": True,
"twitter_message": "Twitter",
},
{
"account_ids": [(4, self.accounts[1].id)],
"message": "Message",
"is_split_per_media": True,
},
]
)
self.assertEqual(post_1.name, "Twitter (Social Post created on 2022-01-02)")
self.assertEqual(post_2.name, "Message (Social Post created on 2022-01-02)")
post_1.twitter_message = "Twitter 2"
self.assertEqual(post_1.name, "Twitter 2 (Social Post created on 2022-01-02)")
@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.addons.social.tests import common
from odoo.addons.social.tests.tools import mock_void_external_calls
from odoo.tests import Form, users
class TestSocialCrmConvert(common.SocialCase):
@classmethod
def setUpClass(cls):
with mock_void_external_calls():
super(TestSocialCrmConvert, cls).setUpClass()
cls.user_social_crm = mail_new_test_user(
cls.env, login='user_social_crm',
name='Christine SocialUser', email='[email protected]',
tz='Europe/Brussels', notification_type='inbox',
company_id=cls.env.ref("base.main_company").id,
groups='base.group_user,social.group_social_user,base.group_partner_manager',
)
cls.utm_campaign_id = cls.env['utm.campaign'].create({
'name': 'Social Campaign'
})
cls.social_stream = cls.env['social.stream'].create({
'name': 'Social Stream',
'stream_type_id': cls.env.ref('social_facebook.stream_type_page_posts').id,
'media_id': cls._get_social_media().id,
'account_id': cls.social_account.id
})
cls.social_post.write({
'utm_campaign_id': cls.utm_campaign_id.id,
})
cls.social_live_post = cls.env['social.live.post'].create({
'post_id': cls.social_post.id,
'account_id': cls.social_account.id,
'facebook_post_id': 'abc123'
})
cls.social_stream_post = cls.env['social.stream.post'].create({
'author_name': 'John Doe',
'stream_id': cls.social_stream.id,
})
@classmethod
def _get_social_media(cls):
return cls.env.ref('social_facebook.social_media_facebook')
@users('user_social_crm')
@mock_void_external_calls()
def test_social_crm_convert_from_post(self):
""" When converting from a stream.post with a matching social.post, the wizard will be
initialized with the data from the stream.post and the resulting lead after conversion will
have as UTMs: the same campaign as the social.post, the medium from the related
social.account and the source as the social.post's source.
Since we found a perfect match on a single partner, the action will be set to 'exist' and
the partner_id will be initialized with this partner. """
self.social_stream_post.write({'facebook_post_id': 'abc123'})
john_doe = self.env['res.partner'].sudo().create({'name': 'John Doe'})
# <form string="Convert Post to Lead">
# ...
# <field name="conversion_source" invisible="1"/>
# <field name="post_content" invisible="1"/>
# ...
# <field name="social_account_id" invisible="1"/>
# <field name="social_stream_post_id" invisible="1"/>
# ...
# </form>
convert_wizard_form = Form(self.env['social.post.to.lead'].with_context(
default_social_account_id=self.social_account,
default_social_stream_post_id=self.social_stream_post,
default_conversion_source='stream_post',
default_post_content='Hello',
))
convert_wizard = convert_wizard_form.save()
self.assertEqual(convert_wizard.post_datetime, self.social_stream_post.published_date)
self.assertEqual(convert_wizard.post_link, self.social_stream_post.post_link)
self.assertEqual(convert_wizard.partner_id, john_doe)
self.assertEqual(convert_wizard.author_name, 'John Doe')
self.assertEqual(convert_wizard.action, 'exist')
convert_wizard.action_convert_to_lead()
created_lead = self.env['crm.lead'].sudo().search([('partner_id', '=', john_doe.id)])
self.assertEqual(len(created_lead), 1)
self.assertEqual(created_lead.campaign_id, self.utm_campaign_id)
self.assertEqual(created_lead.medium_id, self.social_account.utm_medium_id)
self.assertEqual(created_lead.source_id, self.social_post.source_id)
@users('user_social_crm')
@mock_void_external_calls()
def test_social_crm_convert_from_comment(self):
""" When converting from a comment the resulting lead after conversion will have as UTMs:
no campaign, the medium from the related social.account and source set to our master data. """
self.env['res.partner'].sudo().create({'name': 'Doug'})
convert_wizard_form = Form(self.env['social.post.to.lead'].with_context(
default_social_account_id=self.social_account.id,
default_social_stream_post_id=self.social_stream_post.id,
default_conversion_source='comment',
default_post_content='Hello',
default_author_name='Jack',
default_post_link='https://www.facebook.com/1',
))
convert_wizard = convert_wizard_form.save()
self.assertEqual(convert_wizard.action, 'create')
self.assertFalse(convert_wizard.partner_id)
convert_wizard.action_convert_to_lead()
created_lead = self.env['crm.lead'].sudo().search([('partner_id', '=', convert_wizard.partner_id.id)])
self.assertEqual(len(created_lead), 1)
self.assertFalse(created_lead.campaign_id)
self.assertEqual(created_lead.medium_id, self.social_account.utm_medium_id)
self.assertEqual(created_lead.source_id, self.env.ref('social_crm.utm_source_social_post'))
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.social_test_full.tests.common import SocialTestFullCase
from odoo.addons.social.tests.tools import mock_void_external_calls
class SocialYoutube(SocialTestFullCase):
@mock_void_external_calls()
def test_youtube_link(self):
social_post = self.env['social.post'].create({
'account_ids': self.accounts.ids,
'message': 'Check out my great video!',
'youtube_video_id': 'ABC123'
})
social_post.action_post()
# check that the video link is correctly added in posts content
for live_post in social_post.live_post_ids.filtered(
lambda live_post: live_post.account_id.media_type != 'youtube'
):
self.assertTrue('https://youtube.com/watch?v=ABC123' in live_post.message)
# check that the push notification has detected the YouTube link
# and added it as its target URL
self.assertEqual('https://youtube.com/watch?v=ABC123', social_post.push_notification_target_url)