TIP: You can type at any time to perform a new search.
Social Media Advertising
social_media_advertising · OCA/social
🛠 Migration considerations
social_advertising_account_view_tree— View 'social_advertising_account_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · sourcesocial_advertising_ad_view_tree— View 'social_advertising_ad_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · sourcesocial_advertising_campaign_group_view_tree— View 'social_advertising_campaign_group_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · sourcesocial_advertising_campaign_view_tree— View 'social_advertising_campaign_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · sourcesocial_stage_view_tree— View 'social_stage_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · sourcesocial_tag_view_tree— View 'social_tag_view_tree' is defined with a `<tree>` root tag: renamed to `<list>` in Odoo 18.0. migration-view-tree-tag · source
Found by automated static analysis: patterns worth a look before/after upgrading this module to a newer Odoo version.
- Repository
- OCA/social · module folder · Try on Runboat
- Module version
- 1.0.0
- Category
- Social Network
- Folder size
- 0.76 MB
- License
- AGPL-3
- Application
- No
- Auto-installable
- No
- Website
- https://github.com/OCA/social
- Last tracking update
- 2026-09-16 23:05:26
- Authors
- Odoo Community Association (OCA), Binhex
- Maintainers
- Odoo Community Association (OCA), Binhex
- Committers
- OCA-git-bot, oca-ci, Edilio Escalona Almira
- Odoo dependencies
- Python dependencies
- None
- System dependencies
- None
- Required by
- None
- Description
This module adds the advertising layer on top of *Social Media Base*: the campaigns used to promote the posts, the groups that manage several campaigns as a unit, the tags that classify them and the view of the ads served by the social media. Everything is generic, so it works with any social media. Each connector module plugs its own social media through the extension hooks, and contributes its own submenu under *Advertising*: campaign groups, campaigns and ads belong to a single social media, so they are never listed mixed together. Main features: - Campaign groups and campaigns, linked to a social media, to its accounts and to the posts they promote. - A second campaign field on a post, next to the Odoo marketing campaign (`utm.campaign`) that *Social Media Base* provides: the campaign of the social media itself, which holds the budget and the remote reference. The two are independent. - Tags to classify the campaigns. - Stages declared per social media, so every social media keeps its own status vocabulary for campaigns, campaign groups and ads instead of a hardcoded list. - Ads view listing the sponsored creatives of the connected accounts with their status, their campaign and the post they promote. - An extensible hook so each social media module can import its campaigns.
Code Analysis ⓘ
Views touched (24)
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
social_account_view_form_inherit |
social.account.view.form.inherit.advertising | social.account | form | Inherits social_media_base.social_account_view_form |
social_advertising_account_view_form |
social.advertising.account.form | social.advertising.account | form | New |
social_advertising_account_view_search |
social.advertising.account.search | social.advertising.account | search | New |
social_advertising_account_view_tree |
social.advertising.account.tree | social.advertising.account | tree | New |
social_advertising_ad_view_form |
social.advertising.ad.form | social.advertising.ad | form | New |
social_advertising_ad_view_kanban |
social.advertising.ad.kanban | social.advertising.ad | kanban | New |
social_advertising_ad_view_search |
social.advertising.ad.search | social.advertising.ad | search | New |
social_advertising_ad_view_tree |
social.advertising.ad.tree | social.advertising.ad | tree | New |
social_advertising_campaign_group_view_form |
social.advertising.campaign.group.form | social.advertising.campaign.group | form | New |
social_advertising_campaign_group_view_search |
social.advertising.campaign.group.search | social.advertising.campaign.group | search | New |
social_advertising_campaign_group_view_tree |
social.advertising.campaign.group.tree | social.advertising.campaign.group | tree | New |
social_advertising_campaign_view_form |
social.advertising.campaign.form | social.advertising.campaign | form | New |
social_advertising_campaign_view_search |
social.advertising.campaign.search | social.advertising.campaign | search | New |
social_advertising_campaign_view_tree |
social.advertising.campaign.tree | social.advertising.campaign | tree | New |
social_post_account_view_form_inherit |
social.post.account.view.form.inherit.social.media.advertising | social.post.account | form | Inherits social_media_base.social_post_account_view_form |
social_post_account_view_search_inherit |
social.post.account.view.search.inherit.social.media.advertising | social.post.account | search | Inherits social_media_base.social_post_account_view_search |
social_post_view_form_inherit |
social.post.view.form.inherit.social.media.advertising | social.post | form | Inherits social_media_base.social_post_view_form |
social_post_view_search_inherit |
social.post.view.search.inherit.social.media.advertising | social.post | search | Inherits social_media_base.social_post_view_search |
social_post_view_tree_inherit |
social.post.view.tree.inherit.social.media.advertising | social.post | tree | Inherits social_media_base.social_post_view_tree |
social_stage_view_form |
social.stage.form | social.stage | form | New |
social_stage_view_search |
social.stage.search | social.stage | search | New |
social_stage_view_tree |
social.stage.tree | social.stage | tree | New |
social_tag_view_form |
social.tag.form | social.tag | form | New |
social_tag_view_tree |
social.tag.tree | social.tag | tree | New |
HTTP endpoints (0)
No HTTP endpoints found for this module.
Models touched (9)
New fields (9)
-
ad_countIntegercompute='_compute_ad_count' -
ad_idsOne2many → social.advertising.adstring='Ads' args: 'social.advertising.ad', 'account_id' -
ads_need_updateBooleancopy=Falsehelp='The social media has ads this account does not know about yet. It is raised by the cron checking for new ads and cleared by the next synchronization.'readonly=True -
advertising_account_idsOne2many → social.advertising.accountstring='Advertising Accounts' args: 'social.advertising.account', 'account_id' -
advertising_account_urnCharcompute='_compute_advertising_account_urn'help='Remote reference of the advertising account in use, the value the connector modules send to the social media.'store=Truestring='Advertising Account Reference' -
campaign_countIntegercompute='_compute_campaign_counts' -
campaign_group_countIntegercompute='_compute_campaign_counts' -
can_sync_advertising_accountsBooleancompute='_compute_can_sync_advertising_accounts'help='Whether a connector module can list the advertising accounts of this social media.' -
environmentSelectiondefault='test'help='Which entities the advertising APIs answer for this account. In Test the social media only returns the test advertising accounts, their campaigns and their ads, which are never served nor billed. This setting does not affect the publication of posts.'required=True args: ADVERTISING_ENVIRONMENTS
-
action_import_campaigns(self)Import the campaign groups and campaigns from the social media. :return: ``success``, ``message`` and the number of imported ``groups``, ``campaigns`` and ``ads``. :rtype: dict -
action_import_campaigns_notify(self)Import the campaigns and show the result as a notification. The notification chains a soft reload so the campaign counters of the account show what was just imported without the user reloading the view by hand. -
action_open_ads(self)Open the ads of this account. -
action_open_campaign_groups(self)Open the campaign groups of the advertising accounts of this account. -
action_open_campaigns(self)Open the campaigns of the advertising accounts of this account. -
action_sync_ads(self)Fetch the ads from the social media. :return: ``success``, ``message`` and the number of ``ads``. :rtype: dict -
action_sync_advertising_accounts(self)Fetch the advertising accounts from the social media. :return: ``success``, ``message`` and the number of ``accounts``. :rtype: dict -
action_sync_advertising_accounts_notify(self)Fetch the advertising accounts and show the result as a notification. The notification chains a soft reload so the list of advertising accounts shows what was just fetched without the user reloading the view by hand. -
action_sync_all_ads_notify(self)@api.modelFetch the ads of every account the user can see, from the ads view. Each account is synchronized in its own savepoint: the ads the social media already answered for an account must survive the failure of the next one. Errors are summed up in the notification instead of interrupting the run, because the user is looking at the ads of every account at once. -
get_ads_need_update(self)@api.modelReturn whether the accounts of the user have ads to synchronize. The kanban of the ads raises its badge from the bus, but a reload starts from scratch, so the flag stored by the cron has to be read back when the view is mounted. The record rules already restrict the search to the accounts the user is responsible for. :rtype: bool -
write(self, vals)Drop the advertising account in use when the environment changes. The two environments never share an advertising account, so the one that was in use cannot belong to the new one. The new environment may leave a single candidate, which is then chosen right away.
New fields (13)
-
account_idMany2one → social.accountindex=Trueondelete='cascade'required=True args: 'social.account' -
campaign_countIntegercompute='_compute_campaign_counts' -
campaign_group_countIntegercompute='_compute_campaign_counts' -
campaign_group_idsOne2many → social.advertising.campaign.groupargs: 'social.advertising.campaign.group', 'advertising_account_id' -
campaign_idsOne2many → social.advertising.campaignargs: 'social.advertising.campaign', 'advertising_account_id' -
company_idMany2oneindex=Truerelated='account_id.company_id'store=True -
currency_idMany2one → res.currencyhelp='Currency the budgets of this advertising account are denominated in.' args: 'res.currency' -
environmentSelectionhelp='Environment this advertising account belongs to. A test advertising account is never served nor billed.'required=True args: ADVERTISING_ENVIRONMENTS -
is_currentBooleancopy=Falsehelp='Advertising account the campaigns and the ads of this social media account work with. Only one at a time.'string='In Use' -
last_sync_dateDatetimereadonly=Truestring='Last Fetch' -
media_idMany2onerelated='account_id.media_id'store=True -
nameCharrequired=True -
remote_refCharcopy=Falsehelp='Identifier of the advertising account on the social media.'index=Truerequired=Truestring='Remote Reference'
-
action_open_campaign_groups(self)Open the campaign groups of this advertising account. -
action_open_campaigns(self)Open the campaigns of this advertising account. -
action_set_current(self)Choose this advertising account from the account form.
New fields (28)
-
account_idMany2one → social.accountindex=Trueondelete='cascade'required=True args: 'social.account' -
action_click_countIntegerhelp='Clicks on the call to action of the ad.' -
activeBooleandefault=Truehelp='Ads that disappear from the social media are archived instead of deleted, so their statistics are not lost.' -
ad_unit_click_countIntegerhelp='Clicks anywhere on the ad unit itself.' -
advertising_account_idMany2one → social.advertising.accounthelp='Advertising account this ad was served from.'index=Trueondelete='set null' args: 'social.advertising.account' -
advertising_account_is_currentBooleanhelp='Whether the advertising account this ad belongs to is the one the social media account works with right now. Ads of the other advertising accounts are kept as they were last synchronized.'related='advertising_account_id.is_current'store=Truestring='Advertising Account In Use' -
campaign_idMany2one → social.advertising.campaignhelp='Campaign of the social media this ad belongs to.'index=Trueondelete='set null'string='Campaign' args: 'social.advertising.campaign' -
can_delete_remote_adBooleancompute='_compute_can_delete_remote_ad'help='Whether the connector module of this social media deletes an ad, and this one is not gone already.' -
click_countInteger -
company_idMany2oneindex=Truerelated='account_id.company_id'store=True -
conversion_countInteger -
costMonetary -
created_dateDatetimehelp='Moment the ad was created on the social media.'string='Created On' -
currency_idMany2one → res.currencyhelp='Currency the cost is expressed in. It is the one the social media reports, which is not necessarily the one the advertising account is billed in: LinkedIn, for instance, always answers in US dollars.' args: 'res.currency' -
impression_countInteger -
last_sync_dateDatetimereadonly=Truestring='Last Fetch' -
media_idMany2onerelated='account_id.media_id'store=True -
media_typeSelectionrelated='media_id.media_type' -
nameCharcompute='_compute_name'help='Text of the promoted post, or a note saying it is not available when the ad promotes a post this database does not know.'store=True -
post_account_idMany2one → social.post.accounthelp='Publication this ad promotes. It is empty when the promoted post was not created nor imported into this database.'index=Trueondelete='set null'string='Publication' args: 'social.post.account' -
remote_refCharcopy=Falsehelp='Identifier of this ad on the social media.'index=Truerequired=Truestring='Remote Reference' -
stage_codeCharhelp='Status code of the social media, used by the connector modules to tell their own statuses apart in the views.'related='stage_id.code' -
stage_idMany2one → social.stagedomain="[('media_id', '=', media_id), ('applies_to', '=', 'ad')]"help='Status of this ad on the social media.'index=Truestring='Status' args: 'social.stage' -
stage_levelSelectionrelated='stage_id.level' -
statistics_date_fromDatehelp='First day of the window the statistics of this ad cover.'string='Statistics From' -
statistics_date_toDatehelp='Last day of the window the statistics of this ad cover.'string='Statistics To' -
status_detailCharhelp='Reason the social media gives for serving this ad or not.' -
user_idMany2onehelp='Responsible user of the account this ad belongs to. Only that user and the social media administrators can see it.'index=Truerelated='account_id.user_id'store=Truestring='Responsible'
-
action_delete_remote_ad(self)Delete this ad on the social media. The ads mirror the social media and a regular user only reads them, so the permission checked is the one of the account they belong to: its responsible user and the social media administrators. The local record is written with ``sudo()`` afterwards, like the synchronization does. :return: a notification describing what the social media did. :rtype: dict -
action_open_post_account(self)Open the publication this ad promotes. -
action_purge_ad(self)Delete this ad and its history from Odoo. Reserved to the archived ads: one the social media still answers would be created again by the next synchronization, so deleting it only loses its statistics for nothing. :return: the list of ads, since the record it was called on is gone. :rtype: dict
New fields (13)
-
account_idsMany2many → social.accountcolumn1='campaign_id'column2='account_id'domain="[('media_id', 'in', allow_media_ids)]"relation='social_advertising_campaign_account_rel'string='Accounts' args: 'social.account' -
activeBooleandefault=True -
advertising_account_idMany2one → social.advertising.accountcopy=Falsehelp='Advertising account this campaign belongs to on the social media. It is set when the campaign is created there or imported from it, and never changes afterwards, except when the advertising account itself disappears from the social media: it is then dropped and this campaign is left without a link.'index=Trueondelete='set null'readonly=True args: 'social.advertising.account' -
allow_media_idsMany2many → social.mediacompute='_compute_allow_media_ids'string='Allowed Media' args: 'social.media' -
campaign_group_idMany2one → social.advertising.campaign.groupstring='Campaign Group'tracking=True args: 'social.advertising.campaign.group' -
media_idMany2one → social.mediadomain="[('id', 'in', allow_media_ids)]"string='Media' args: 'social.media' -
media_typeSelectionrelated='media_id.media_type' -
nameCharrequired=Truetracking=True -
remote_refCharcopy=Falsehelp='Identifier of this campaign on the social media. It is set by the connector module of each social media.'index=Truestring='Remote Reference' -
stage_idMany2one → social.stagecopy=Falsedomain="[('media_id', '=', media_id), ('applies_to', '=', 'campaign')]"help='Status of this campaign on the social media.'index=Truestring='Stage'tracking=True args: 'social.stage' -
stage_levelSelectionrelated='stage_id.level' -
tag_idsMany2many → social.tagcolumn1='campaign_id'column2='tag_id'relation='social_advertising_campaign_tag_rel'string='Tags' args: 'social.tag' -
user_idMany2one → res.usersdefault=<expr>help='User this campaign belongs to. Only the responsible user and the social media administrators can see it.'index=Truerequired=Truestring='Responsible'tracking=True args: 'res.users'
No public methods.
New fields (10)
-
activeBooleandefault=True -
advertising_account_idMany2one → social.advertising.accountcopy=Falsehelp='Advertising account this campaign group belongs to on the social media. It is set when the campaign group is created there or imported from it, and never changes afterwards, except when the advertising account itself disappears from the social media: it is then dropped and this campaign group is left without a link.'index=Trueondelete='set null'readonly=True args: 'social.advertising.account' -
campaign_countIntegercompute='_compute_campaign_count' -
campaign_idsOne2many → social.advertising.campaignargs: 'social.advertising.campaign', 'campaign_group_id' -
media_idMany2one → social.mediacompute='_compute_media_id'help='Social media of the campaigns of this group. Deduced from the campaigns; editable while the group has none, which is how a connector module knows the social media of a group created empty.'readonly=Falsestore=Truestring='Media' args: 'social.media' -
media_typeSelectionrelated='media_id.media_type' -
nameCharrequired=Truetracking=True -
remote_refCharcopy=Falsehelp='Identifier of this campaign group on the social media. It is set by the connector module of each social media.'index=Truestring='Remote Reference' -
stage_idMany2one → social.stagecopy=Falsedomain="[('media_id', '=', media_id), ('applies_to', '=', 'group')]"help='Status of this campaign group on the social media.'index=Truestring='Stage'tracking=True args: 'social.stage' -
stage_levelSelectionrelated='stage_id.level'
-
action_view_campaigns(self)Open the campaigns linked to this campaign group.
New fields (2)
-
allow_social_campaign_idsMany2many → social.advertising.campaigncompute='_compute_allow_social_campaign_ids'help='Social media campaigns that can be linked to this post.' args: 'social.advertising.campaign' -
social_campaign_idMany2one → social.advertising.campaignargs: 'social.advertising.campaign'
No public methods.
New fields (1)
-
social_campaign_idMany2one → social.advertising.campaigncompute='_compute_social_campaign_id'help='Social media campaign of the parent post. A publication imported from the social media has no parent post, so its campaign is resolved by the connector module from the remote one.'readonly=Falsestore=True args: 'social.advertising.campaign'
No public methods.
New fields (7)
-
applies_toSelectiondefault='campaign'help='Records this stage can be set on.'required=True args: [('campaign', 'Campaign'), ('group', 'Campaign Group'), ('ad', 'Ad')] -
codeCharhelp='Status value as returned by the social media, used by the connector module to map the remote status to this stage.'required=True -
foldBooleanhelp='Fold the column of this stage in the kanban views.' -
levelSelectiondefault='secondary'help='Colour of the badge showing this stage.' args: [('success', 'Success'), ('info', 'Info'), ('warning', 'Warning'), ('danger', 'Danger'), ('secondary', 'Secondary')] -
media_idMany2one → social.mediaindex=Trueondelete='cascade'required=True args: 'social.media' -
nameCharrequired=Truetranslate=True -
sequenceIntegerdefault=10
No public methods.
New fields (1)
-
nameCharrequired=True
No public methods.