Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Release History

13.0.24(2025-02-20)
+++++++++++++++++++++++++
* Update Bing Ads API Version 13 service proxies to reflect recent interface changes. For details please see the Bing Ads API Release Notes: https://learn.microsoft.com/en-us/advertising/guides/release-notes?view=bingads-13.
* Added NewCustomerAcquisitionGoalSetting in BulkCampaign mapping.
* Added SubType, ActionType in BulkCampaignConversionGoal mapping.
* Added CampaignId in BulkKeyword mapping.
* Added bulk mappings for NCA: BulkNewCustomerAcquisitionGoal.

13.0.23.1(2025-01-23)
+++++++++++++++++++++++++
* Update Bing Ads API Version 13 service proxies to reflect recent interface changes. For details please see the Bing Ads API Release Notes: https://learn.microsoft.com/en-us/advertising/guides/release-notes?view=bingads-13.
Expand Down
2 changes: 1 addition & 1 deletion bingads/manifest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
VERSION = '13.0.23.1'
VERSION = '13.0.24'
BULK_FORMAT_VERSION_6 = '6.0'
WORKING_NAME = 'BingAdsSDKPython'
USER_AGENT = '{0} {1} {2}'.format(WORKING_NAME, VERSION, sys.version_info[0:3])
1 change: 1 addition & 0 deletions bingads/v13/bulk/entities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@
from .bulk_campaign_brand_list_association import *
from .bulk_brand_item import *
from .bulk_brand_list import *
from .bulk_new_customer_acquisition_goal import *
from .goals import *
21 changes: 20 additions & 1 deletion bingads/v13/bulk/entities/bulk_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ class BulkBudget(_SingleRecordBulkEntity):
* :class:`.BulkFileWriter`
"""

def __init__(self, budget=None, status=None, account_id=None):
def __init__(self, budget=None, status=None, account_id=None, campaign_id=None):
super(BulkBudget, self).__init__()
self._budget = budget
self._status = status
self._account_id = account_id
self._campaign_id = campaign_id

@property
def budget(self):
Expand Down Expand Up @@ -63,6 +64,19 @@ def account_id(self):
def account_id(self, value):
self._account_id = value

@property
def campaign_id(self):
""" the id of the campaign which contains the budget
Corresponds to the 'Campaign Id' field in the bulk file.

:rtype: long
"""
return self._campaign_id

@campaign_id.setter
def campaign_id(self, value):
self._campaign_id = value


_MAPPINGS = [
_SimpleBulkMapping(
Expand All @@ -75,6 +89,11 @@ def account_id(self, value):
field_to_csv=lambda c: bulk_str(c.account_id),
csv_to_field=lambda c, v: setattr(c, 'account_id', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.CampaignId,
field_to_csv=lambda c: bulk_str(c.campaign_id),
csv_to_field=lambda c, v: setattr(c, 'campaign_id', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.Status,
field_to_csv=lambda c: c.status,
Expand Down
87 changes: 87 additions & 0 deletions bingads/v13/bulk/entities/bulk_campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping, _ComplexBulkMapping
from bingads.v13.internal.extensions import *
from decimal import Decimal

_DynamicFeedSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('DynamicFeedSetting'))
_TargetSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('TargetSetting'))
Expand All @@ -12,6 +13,7 @@
_DisclaimerSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('DisclaimerSetting'))
_VerifiedTrackingSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('VerifiedTrackingSetting'))
_PerformanceMaxSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('PerformanceMaxSetting'))
_NewCustomerAcquisitionGoalSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('NewCustomerAcquisitionGoalSetting'))

class BulkCampaign(_SingleRecordBulkEntity):
""" Represents a campaign that can be read or written in a bulk file.
Expand Down Expand Up @@ -167,6 +169,9 @@ def _get_verified_tracking_setting(self):
def _get_performance_max_setting(self):
return self._get_setting(_PerformanceMaxSetting, 'PerformanceMaxSetting')

def _get_new_customer_acquisition_goal_setting(self):
return self._get_setting(_NewCustomerAcquisitionGoalSetting, 'NewCustomerAcquisitionGoalSetting')

def _get_setting(self, setting_type, setting_name):
if not self.campaign.Settings.Setting:
return None
Expand Down Expand Up @@ -205,6 +210,7 @@ def _read_campaign_type(c, v):
if campaign_type.lower() == 'performancemax':
BulkCampaign._create_campaign_setting(c.campaign, 'PerformanceMaxSetting')
BulkCampaign._create_campaign_setting(c.campaign, 'ShoppingSetting')
BulkCampaign._create_campaign_setting(c.campaign, 'NewCustomerAcquisitionGoalSetting')

@staticmethod
def _create_campaign_setting(campaign, setting_type):
Expand Down Expand Up @@ -521,6 +527,72 @@ def _write_image_opt_out(c):
return None
return bulk_str(performance_max_setting.AutoGeneratedImageOptOut)

@staticmethod
def _read_new_customer_acquisition_bid_only_mode(c, v):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
new_customer_acquisition_goal_setting.NewCustomerAcquisitionBidOnlyMode = parse_bool(v)

@staticmethod
def _write_new_customer_acquisition_bid_only_mode(c):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
return bulk_str(new_customer_acquisition_goal_setting.NewCustomerAcquisitionBidOnlyMode)

@staticmethod
def _read_new_customer_acquisition_goal_id(c, v):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
new_customer_acquisition_goal_setting.NewCustomerAcquisitionGoalId = int(v) if v else None

@staticmethod
def _write_new_customer_acquisition_goal_id(c):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
return bulk_str(new_customer_acquisition_goal_setting.NewCustomerAcquisitionGoalId)

@staticmethod
def _read_additional_conversion_value(c, v):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
new_customer_acquisition_goal_setting.AdditionalConversionValue = Decimal(v) if v else None

@staticmethod
def _write_additional_conversion_value(c):
if not c.campaign.CampaignType:
return None
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
if 'performancemax' in campgaign_types:
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
if not new_customer_acquisition_goal_setting:
return None
return bulk_str(new_customer_acquisition_goal_setting.AdditionalConversionValue)

@staticmethod
def _read_website(c, v):
if not c.campaign.CampaignType:
Expand Down Expand Up @@ -756,6 +828,21 @@ def _write_website(c):
field_to_csv=lambda c: field_to_csv_bool(c.should_serve_on_msan),
csv_to_field=lambda c, v: setattr(c, 'should_serve_on_msan', parse_bool(v))
),
_SimpleBulkMapping(
header=_StringTable.NewCustomerAcquisitionGoalId,
field_to_csv=lambda c: BulkCampaign._write_new_customer_acquisition_goal_id(c),
csv_to_field=lambda c, v: BulkCampaign._read_new_customer_acquisition_goal_id(c, v)
),
_SimpleBulkMapping(
header=_StringTable.NewCustomerAcquisitionBidOnlyMode,
field_to_csv=lambda c: BulkCampaign._write_new_customer_acquisition_bid_only_mode(c),
csv_to_field=lambda c, v: BulkCampaign._read_new_customer_acquisition_bid_only_mode(c, v)
),
_SimpleBulkMapping(
header=_StringTable.AdditionalConversionValue,
field_to_csv=lambda c: BulkCampaign._write_additional_conversion_value(c),
csv_to_field=lambda c, v: BulkCampaign._read_additional_conversion_value(c, v)
),
]

def read_additional_data(self, stream_reader):
Expand Down
43 changes: 39 additions & 4 deletions bingads/v13/bulk/entities/bulk_campaign_conversion_goal.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class BulkCampaignConversionGoal(_SingleRecordBulkEntity):

Properties of this class and of classes that it is derived from, correspond to fields of the CampaignConversionGoal record in a bulk file.
For more information, see CampaignConversionGoal at https://go.microsoft.com/fwlink/?linkid=846127

*See also:*

* :class:`.BulkServiceManager`
Expand All @@ -19,10 +19,11 @@ class BulkCampaignConversionGoal(_SingleRecordBulkEntity):
* :class:`.BulkFileWriter`
"""

def __init__(self, campaign_conversion_goal = None):
def __init__(self, campaign_conversion_goal = None, sub_type = None, action_type = None):
super(BulkCampaignConversionGoal, self).__init__()
self._campaign_conversion_goal = campaign_conversion_goal

self._sub_type = sub_type
self._action_type = action_type

@property
def campaign_conversion_goal(self):
Expand All @@ -34,7 +35,31 @@ def campaign_conversion_goal(self):

@campaign_conversion_goal.setter
def campaign_conversion_goal(self, value):
self._campaign_conversion_goal = value
self._campaign_conversion_goal = value

@property
def sub_type(self):
""" Corresponds to the 'Sub Type' field in the bulk file.

:rtype: str
"""
return self._sub_type

@sub_type.setter
def sub_type(self, value):
self._sub_type = value

@property
def action_type(self):
""" Corresponds to the 'Action Type' field in the bulk file.

:rtype: str
"""
return self._action_type

@action_type.setter
def action_type(self, value):
self._action_type = value


_MAPPINGS = [
Expand All @@ -48,6 +73,16 @@ def campaign_conversion_goal(self, value):
field_to_csv=lambda c: bulk_str(c.campaign_conversion_goal.GoalId),
csv_to_field=lambda c, v: setattr(c.campaign_conversion_goal, 'GoalId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.ActionType,
field_to_csv=lambda c: c.action_type,
csv_to_field=lambda c, v: setattr(c, 'action_type', v)
),
_SimpleBulkMapping(
header=_StringTable.SubType,
field_to_csv=lambda c: c.sub_type,
csv_to_field=lambda c, v: setattr(c, 'sub_type', v)
),
]

def process_mappings_from_row_values(self, row_values):
Expand Down
81 changes: 81 additions & 0 deletions bingads/v13/bulk/entities/bulk_new_customer_acquisition_goal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V13
from bingads.v13.internal.bulk.string_table import _StringTable
from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
from bingads.v13.internal.extensions import *
from decimal import Decimal


class BulkNewCustomerAcquisitionGoal (_SingleRecordBulkEntity):
""" Represents a new customer acquisition goal that can be read or written in a bulk file.

Properties of this class and of classes that it is derived from, correspond to fields of the Budget record in a bulk file.
For more information, see Budget at https://go.microsoft.com/fwlink/?linkid=846127

*See also:*

* :class:`.BulkServiceManager`
* :class:`.BulkOperation`
* :class:`.BulkFileReader`
* :class:`.BulkFileWriter`
"""

def __init__(self, new_customer_acquisition_goal=None, target=None):
super(BulkNewCustomerAcquisitionGoal , self).__init__()
self._new_customer_acquisition_goal = new_customer_acquisition_goal
self._target = target

@property
def new_customer_acquisition_goal (self):
"""
the NewCustomerAcquisitionGoal object, see more detail at: https://go.microsoft.com/fwlink/?linkid=846127
"""
return self._new_customer_acquisition_goal

@new_customer_acquisition_goal .setter
def new_customer_acquisition_goal (self, value):
self._new_customer_acquisition_goal = value

@property
def target(self):
"""
The ids of audiences within the new customer acquisition.
It should be split by simicolon. example: "123;456;789"
Corresponds to 'Target' field in bulk file.
:rtype: str
"""
return self._target

@target.setter
def target(self, value):
self._target = value


_MAPPINGS = [
_SimpleBulkMapping(
header=_StringTable.Id,
field_to_csv=lambda c: bulk_str(c.new_customer_acquisition_goal .Id),
csv_to_field=lambda c, v: setattr(c.new_customer_acquisition_goal , 'Id', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.Target,
field_to_csv=lambda c: bulk_str(c.target),
csv_to_field=lambda c, v: setattr(c, 'target', v)
),
_SimpleBulkMapping(
header=_StringTable.AdditionalConversionValue,
field_to_csv=lambda c: bulk_str(c.new_customer_acquisition_goal.AdditionalValue),
csv_to_field=lambda c, v: setattr(c.new_customer_acquisition_goal , 'AdditionalValue', Decimal(v) if v else None)
),
]

def process_mappings_from_row_values(self, row_values):
self._new_customer_acquisition_goal = _CAMPAIGN_OBJECT_FACTORY_V13.create('NewCustomerAcquisitionGoal')
row_values.convert_to_entity(self, BulkNewCustomerAcquisitionGoal ._MAPPINGS)

def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
self._validate_property_not_null(self.new_customer_acquisition_goal , 'new_customer_acquisition_goal ')
self.convert_to_values(row_values, BulkNewCustomerAcquisitionGoal ._MAPPINGS)

def read_additional_data(self, stream_reader):
super(BulkNewCustomerAcquisitionGoal , self).read_additional_data(stream_reader)
1 change: 1 addition & 0 deletions bingads/v13/internal/bulk/bulk_object_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class _BulkObjectFactory():
_StringTable.BrandItem: _EntityInfo(lambda: BulkBrandItem()),
_StringTable.CampaignBrandList: _EntityInfo(lambda: BulkCampaignBrandListAssociation()),
_StringTable.AssetGroupUrlTarget: _EntityInfo(lambda: BulkAssetGroupUrlTarget()),
_StringTable.NewCustomerAcquisitionGoal: _EntityInfo(lambda: BulkNewCustomerAcquisitionGoal()),
}

ADDITIONAL_OBJECT_MAP = {
Expand Down
7 changes: 7 additions & 0 deletions bingads/v13/internal/bulk/csv_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class _CsvHeaders:
_StringTable.Status,
_StringTable.Id,
_StringTable.ParentId,
_StringTable.CampaignId,
_StringTable.SubType,
_StringTable.Campaign,
_StringTable.AdGroup,
Expand Down Expand Up @@ -528,6 +529,12 @@ class _CsvHeaders:
_StringTable.AssetGroupTargetValue1,
_StringTable.AssetGroupTargetValue2,
_StringTable.AssetGroupTargetValue3,

# New Customer Acquisition Goal
_StringTable.AdditionalConversionValue,
_StringTable.NewCustomerAcquisitionGoalId,
_StringTable.NewCustomerAcquisitionBidOnlyMode,

]

@staticmethod
Expand Down
Loading