diff --git a/facebook_business/adobjects/serverside/action_source.py b/facebook_business/adobjects/serverside/action_source.py index e3c8e228..6610c3c9 100644 --- a/facebook_business/adobjects/serverside/action_source.py +++ b/facebook_business/adobjects/serverside/action_source.py @@ -60,6 +60,11 @@ class ActionSource(Enum): """ SYSTEM_GENERATED = 'system_generated' + """ + Conversion happened through a business messaging channel, such as WhatsApp or Instagram Direct. + """ + BUSINESS_MESSAGING = 'business_messaging' + """ Conversion happened in a way that is not listed. """ diff --git a/facebook_business/adobjects/serverside/event.py b/facebook_business/adobjects/serverside/event.py index 07ba0d83..20ef8b79 100644 --- a/facebook_business/adobjects/serverside/event.py +++ b/facebook_business/adobjects/serverside/event.py @@ -25,6 +25,7 @@ from facebook_business.adobjects.serverside.custom_data import CustomData from facebook_business.adobjects.serverside.user_data import UserData from facebook_business.adobjects.serverside.app_data import AppData +from facebook_business.adobjects.serverside.messaging_channel import MessagingChannel class Event(object): @@ -42,12 +43,13 @@ class Event(object): 'data_processing_options_state': 'int', 'action_source': 'ActionSource', 'advanced_measurement_table': 'str', + 'messaging_channel': 'MessagingChannel', } def __init__(self, event_name = None, event_time = None, event_source_url = None, opt_out = None, event_id = None, user_data = None, custom_data = None, app_data = None, data_processing_options = None, data_processing_options_country = None, - data_processing_options_state = None, action_source = None, advanced_measurement_table = None): + data_processing_options_state = None, action_source = None, advanced_measurement_table = None, messaging_channel = None): # type: (str, int, str, bool, str, UserData, CustomData, AppData, list[str], int, int, ActionSource, str) -> None """Conversions API Event""" @@ -66,6 +68,7 @@ def __init__(self, event_name = None, event_time = None, event_source_url = None self._advanced_measurement_table = None self.event_name = event_name self.event_time = event_time + self._messaging_channel = None if event_source_url is not None: self.event_source_url = event_source_url if opt_out is not None: @@ -88,6 +91,8 @@ def __init__(self, event_name = None, event_time = None, event_source_url = None self.action_source = action_source if advanced_measurement_table is not None: self.advanced_measurement_table = advanced_measurement_table + if messaging_channel is not None: + self.messaging_channel = messaging_channel @property def event_name(self): @@ -402,6 +407,28 @@ def advanced_measurement_table(self, advanced_measurement_table): """ self._advanced_measurement_table = advanced_measurement_table + @property + def messaging_channel(self): + """Gets the messaging_channel. + + Return the messaging channel of the event. + + :return: The messaging_channel. + :rtype: str + """ + return self._messaging_channel + + @messaging_channel.setter + def messaging_channel(self, messaging_channel): + """Sets the advanced_measurement_table. + + Allow you to specify the messaging channel of the event. + + :param messaging_channel: The messaging_channel. + :type: str + """ + self._messaging_channel = messaging_channel + def normalize(self): normalized_payload = {'event_name': self.event_name, 'event_time': self.event_time, 'event_source_url': self.event_source_url, 'opt_out': self.opt_out, @@ -423,6 +450,10 @@ def normalize(self): self.validate_action_source(self.action_source) normalized_payload['action_source'] = self.action_source.value + if self.messaging_channel is not None: + self.validate_messaging_channel(self.messaging_channel) + normalized_payload['messaging_channel'] = self.messaging_channel.value + normalized_payload = {k: v for k, v in normalized_payload.items() if v is not None} return normalized_payload @@ -432,6 +463,13 @@ def validate_action_source(self, action_source): 'action_source must be an ActionSource. TypeError on value: %s' % action_source ) + def validate_messaging_channel(self, messaging_channel): + if not type(messaging_channel) == MessagingChannel: + raise TypeError( + 'messaging_channel must be an messaging_channel. TypeError on value: %s' % messaging_channel + ) + + def to_dict(self): """Returns the model properties as a dict""" result = {} diff --git a/facebook_business/adobjects/serverside/messaging_channel.py b/facebook_business/adobjects/serverside/messaging_channel.py new file mode 100644 index 00000000..ce0572c5 --- /dev/null +++ b/facebook_business/adobjects/serverside/messaging_channel.py @@ -0,0 +1,32 @@ +# Copyright 2014 Facebook, Inc. + +# You are hereby granted a non-exclusive, worldwide, royalty-free license to +# use, copy, modify, and distribute this software in source code or binary +# form for use in connection with the web services and APIs provided by +# Facebook. + +# As with any software that integrates with the Facebook platform, your use +# of this software is subject to the Facebook Developer Principles and +# Policies [http://developers.facebook.com/policy/]. This copyright notice +# shall be included in all copies or substantial portions of the software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from enum import Enum + + +# Used to specify which messaging channel was used. +# See https://developers.facebook.com/docs/marketing-api/conversions-api/business-messaging + +class MessagingChannel(Enum): + + """ + Conversion happened on WhatsApp. + """ + WHATSAPP = 'whatsapp' diff --git a/facebook_business/adobjects/serverside/user_data.py b/facebook_business/adobjects/serverside/user_data.py index 0325209a..8c7598d4 100644 --- a/facebook_business/adobjects/serverside/user_data.py +++ b/facebook_business/adobjects/serverside/user_data.py @@ -55,6 +55,8 @@ class UserData(object): 'doby': 'str', 'madid': 'str', 'anon_id': 'str', + 'ctwa_clid': 'ctwa_clid', + 'page_id': 'page_id', } def __init__( @@ -96,8 +98,10 @@ def __init__( external_ids=None, madid=None, anon_id=None, + ctwa_clid=None, + page_id=None, ): - # type: (str, str, Gender, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, list[str], list[str], list[Gender], list[str], list[str], list[str], list[str], list[str], list[str], list[str], list[str], str, str) -> None + # type: (str, str, Gender, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, list[str], list[str], list[Gender], list[str], list[str], list[str], list[str], list[str], list[str], list[str], list[str], str, str, str, str) -> None """UserData is a set of identifiers Facebook can use for targeted attribution""" self._emails = None @@ -126,6 +130,8 @@ def __init__( self._doby = None self._madid = None self._anon_id = None + self._ctwa_clid = None + self._page_id = None if email is not None and emails is not None: raise ValueError(UserData.multi_value_constructor_err.format('email', 'emails')) @@ -225,6 +231,10 @@ def __init__( self.madid = madid if anon_id is not None: self.anon_id = anon_id + if ctwa_clid is not None: + self.ctwa_clid = ctwa_clid + if page_id is not None: + self.page_id = page_id @property def email(self): @@ -1079,6 +1089,22 @@ def anon_id(self): def anon_id(self, anon_id): self._anon_id = anon_id + @property + def ctwa_clid(self): + return self._ctwa_clid + + @ctwa_clid.setter + def ctwa_clid(self, ctwa_clid): + self._ctwa_clid = ctwa_clid + + @property + def page_id(self): + return self._page_id + + @page_id.setter + def page_id(self, page_id): + self._page_id = page_id + def normalize(self): normalized_payload = {'em': self.__normalize_list('em', self.emails), 'ph': self.__normalize_list('ph', self.phones), @@ -1105,6 +1131,8 @@ def normalize(self): 'doby': Normalize.normalize_field('doby', self.doby), 'madid': self.madid, 'anon_id': self.anon_id, + 'ctwa_clid': self.ctwa_clid, + 'page_id': self.page_id, } if self.genders: normalized_payload['ge'] = self.__normalize_list('ge', list(map(lambda g: g.value, self.genders)))