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
OCA/social:
odoo/odoo:
- utm
- web
- bus
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 IDNameModelTypeStatus
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_count Integer
    compute='_compute_ad_count'
  • ad_ids One2many → social.advertising.ad
    string='Ads' args: 'social.advertising.ad', 'account_id'
  • ads_need_update Boolean
    copy=False help='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_ids One2many → social.advertising.account
    string='Advertising Accounts' args: 'social.advertising.account', 'account_id'
  • advertising_account_urn Char
    compute='_compute_advertising_account_urn' help='Remote reference of the advertising account in use, the value the connector modules send to the social media.' store=True string='Advertising Account Reference'
  • campaign_count Integer
    compute='_compute_campaign_counts'
  • campaign_group_count Integer
    compute='_compute_campaign_counts'
  • can_sync_advertising_accounts Boolean
    compute='_compute_can_sync_advertising_accounts' help='Whether a connector module can list the advertising accounts of this social media.'
  • environment Selection
    default='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
Public methods (11)
  • 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.model
    Fetch 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.model
    Return 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_id Many2one → social.account
    index=True ondelete='cascade' required=True args: 'social.account'
  • campaign_count Integer
    compute='_compute_campaign_counts'
  • campaign_group_count Integer
    compute='_compute_campaign_counts'
  • campaign_group_ids One2many → social.advertising.campaign.group
    args: 'social.advertising.campaign.group', 'advertising_account_id'
  • campaign_ids One2many → social.advertising.campaign
    args: 'social.advertising.campaign', 'advertising_account_id'
  • company_id Many2one
    index=True related='account_id.company_id' store=True
  • currency_id Many2one → res.currency
    help='Currency the budgets of this advertising account are denominated in.' args: 'res.currency'
  • environment Selection
    help='Environment this advertising account belongs to. A test advertising account is never served nor billed.' required=True args: ADVERTISING_ENVIRONMENTS
  • is_current Boolean
    copy=False help='Advertising account the campaigns and the ads of this social media account work with. Only one at a time.' string='In Use'
  • last_sync_date Datetime
    readonly=True string='Last Fetch'
  • media_id Many2one
    related='account_id.media_id' store=True
  • name Char
    required=True
  • remote_ref Char
    copy=False help='Identifier of the advertising account on the social media.' index=True required=True string='Remote Reference'
Public methods (3)
  • 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_id Many2one → social.account
    index=True ondelete='cascade' required=True args: 'social.account'
  • action_click_count Integer
    help='Clicks on the call to action of the ad.'
  • active Boolean
    default=True help='Ads that disappear from the social media are archived instead of deleted, so their statistics are not lost.'
  • ad_unit_click_count Integer
    help='Clicks anywhere on the ad unit itself.'
  • advertising_account_id Many2one → social.advertising.account
    help='Advertising account this ad was served from.' index=True ondelete='set null' args: 'social.advertising.account'
  • advertising_account_is_current Boolean
    help='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=True string='Advertising Account In Use'
  • campaign_id Many2one → social.advertising.campaign
    help='Campaign of the social media this ad belongs to.' index=True ondelete='set null' string='Campaign' args: 'social.advertising.campaign'
  • can_delete_remote_ad Boolean
    compute='_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_count Integer
  • company_id Many2one
    index=True related='account_id.company_id' store=True
  • conversion_count Integer
  • cost Monetary
  • created_date Datetime
    help='Moment the ad was created on the social media.' string='Created On'
  • currency_id Many2one → res.currency
    help='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_count Integer
  • last_sync_date Datetime
    readonly=True string='Last Fetch'
  • media_id Many2one
    related='account_id.media_id' store=True
  • media_type Selection
    related='media_id.media_type'
  • name Char
    compute='_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_id Many2one → social.post.account
    help='Publication this ad promotes. It is empty when the promoted post was not created nor imported into this database.' index=True ondelete='set null' string='Publication' args: 'social.post.account'
  • remote_ref Char
    copy=False help='Identifier of this ad on the social media.' index=True required=True string='Remote Reference'
  • stage_code Char
    help='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_id Many2one → social.stage
    domain="[('media_id', '=', media_id), ('applies_to', '=', 'ad')]" help='Status of this ad on the social media.' index=True string='Status' args: 'social.stage'
  • stage_level Selection
    related='stage_id.level'
  • statistics_date_from Date
    help='First day of the window the statistics of this ad cover.' string='Statistics From'
  • statistics_date_to Date
    help='Last day of the window the statistics of this ad cover.' string='Statistics To'
  • status_detail Char
    help='Reason the social media gives for serving this ad or not.'
  • user_id Many2one
    help='Responsible user of the account this ad belongs to. Only that user and the social media administrators can see it.' index=True related='account_id.user_id' store=True string='Responsible'
Public methods (3)
  • 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_ids Many2many → social.account
    column1='campaign_id' column2='account_id' domain="[('media_id', 'in', allow_media_ids)]" relation='social_advertising_campaign_account_rel' string='Accounts' args: 'social.account'
  • active Boolean
    default=True
  • advertising_account_id Many2one → social.advertising.account
    copy=False help='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=True ondelete='set null' readonly=True args: 'social.advertising.account'
  • allow_media_ids Many2many → social.media
    compute='_compute_allow_media_ids' string='Allowed Media' args: 'social.media'
  • campaign_group_id Many2one → social.advertising.campaign.group
    string='Campaign Group' tracking=True args: 'social.advertising.campaign.group'
  • media_id Many2one → social.media
    domain="[('id', 'in', allow_media_ids)]" string='Media' args: 'social.media'
  • media_type Selection
    related='media_id.media_type'
  • name Char
    required=True tracking=True
  • remote_ref Char
    copy=False help='Identifier of this campaign on the social media. It is set by the connector module of each social media.' index=True string='Remote Reference'
  • stage_id Many2one → social.stage
    copy=False domain="[('media_id', '=', media_id), ('applies_to', '=', 'campaign')]" help='Status of this campaign on the social media.' index=True string='Stage' tracking=True args: 'social.stage'
  • stage_level Selection
    related='stage_id.level'
  • tag_ids Many2many → social.tag
    column1='campaign_id' column2='tag_id' relation='social_advertising_campaign_tag_rel' string='Tags' args: 'social.tag'
  • user_id Many2one → res.users
    default=<expr> help='User this campaign belongs to. Only the responsible user and the social media administrators can see it.' index=True required=True string='Responsible' tracking=True args: 'res.users'
Public methods (0)

No public methods.

New fields (10)
  • active Boolean
    default=True
  • advertising_account_id Many2one → social.advertising.account
    copy=False help='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=True ondelete='set null' readonly=True args: 'social.advertising.account'
  • campaign_count Integer
    compute='_compute_campaign_count'
  • campaign_ids One2many → social.advertising.campaign
    args: 'social.advertising.campaign', 'campaign_group_id'
  • media_id Many2one → social.media
    compute='_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=False store=True string='Media' args: 'social.media'
  • media_type Selection
    related='media_id.media_type'
  • name Char
    required=True tracking=True
  • remote_ref Char
    copy=False help='Identifier of this campaign group on the social media. It is set by the connector module of each social media.' index=True string='Remote Reference'
  • stage_id Many2one → social.stage
    copy=False domain="[('media_id', '=', media_id), ('applies_to', '=', 'group')]" help='Status of this campaign group on the social media.' index=True string='Stage' tracking=True args: 'social.stage'
  • stage_level Selection
    related='stage_id.level'
Public methods (1)
  • action_view_campaigns(self)
    Open the campaigns linked to this campaign group.

New fields (2)
  • allow_social_campaign_ids Many2many → social.advertising.campaign
    compute='_compute_allow_social_campaign_ids' help='Social media campaigns that can be linked to this post.' args: 'social.advertising.campaign'
  • social_campaign_id Many2one → social.advertising.campaign
    args: 'social.advertising.campaign'
Public methods (0)

No public methods.

New fields (1)
  • social_campaign_id Many2one → social.advertising.campaign
    compute='_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=False store=True args: 'social.advertising.campaign'
Public methods (0)

No public methods.

New fields (7)
  • applies_to Selection
    default='campaign' help='Records this stage can be set on.' required=True args: [('campaign', 'Campaign'), ('group', 'Campaign Group'), ('ad', 'Ad')]
  • code Char
    help='Status value as returned by the social media, used by the connector module to map the remote status to this stage.' required=True
  • fold Boolean
    help='Fold the column of this stage in the kanban views.'
  • level Selection
    default='secondary' help='Colour of the badge showing this stage.' args: [('success', 'Success'), ('info', 'Info'), ('warning', 'Warning'), ('danger', 'Danger'), ('secondary', 'Secondary')]
  • media_id Many2one → social.media
    index=True ondelete='cascade' required=True args: 'social.media'
  • name Char
    required=True translate=True
  • sequence Integer
    default=10
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.