Skip to content

Commit 9f80b4f

Browse files
authored
Merge pull request #310 from BingAds/v13.0.24
v13.0.24
2 parents a7926cd + da4337d commit 9f80b4f

18 files changed

+1521
-65
lines changed

HISTORY.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
33
Release History
44

5+
13.0.24(2025-02-20)
6+
+++++++++++++++++++++++++
7+
* 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.
8+
* Added NewCustomerAcquisitionGoalSetting in BulkCampaign mapping.
9+
* Added SubType, ActionType in BulkCampaignConversionGoal mapping.
10+
* Added CampaignId in BulkKeyword mapping.
11+
* Added bulk mappings for NCA: BulkNewCustomerAcquisitionGoal.
12+
513
13.0.23.1(2025-01-23)
614
+++++++++++++++++++++++++
715
* 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.

bingads/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sys
2-
VERSION = '13.0.23.1'
2+
VERSION = '13.0.24'
33
BULK_FORMAT_VERSION_6 = '6.0'
44
WORKING_NAME = 'BingAdsSDKPython'
55
USER_AGENT = '{0} {1} {2}'.format(WORKING_NAME, VERSION, sys.version_info[0:3])

bingads/v13/bulk/entities/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@
5555
from .bulk_campaign_brand_list_association import *
5656
from .bulk_brand_item import *
5757
from .bulk_brand_list import *
58+
from .bulk_new_customer_acquisition_goal import *
5859
from .goals import *

bingads/v13/bulk/entities/bulk_budget.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ class BulkBudget(_SingleRecordBulkEntity):
2020
* :class:`.BulkFileWriter`
2121
"""
2222

23-
def __init__(self, budget=None, status=None, account_id=None):
23+
def __init__(self, budget=None, status=None, account_id=None, campaign_id=None):
2424
super(BulkBudget, self).__init__()
2525
self._budget = budget
2626
self._status = status
2727
self._account_id = account_id
28+
self._campaign_id = campaign_id
2829

2930
@property
3031
def budget(self):
@@ -63,6 +64,19 @@ def account_id(self):
6364
def account_id(self, value):
6465
self._account_id = value
6566

67+
@property
68+
def campaign_id(self):
69+
""" the id of the campaign which contains the budget
70+
Corresponds to the 'Campaign Id' field in the bulk file.
71+
72+
:rtype: long
73+
"""
74+
return self._campaign_id
75+
76+
@campaign_id.setter
77+
def campaign_id(self, value):
78+
self._campaign_id = value
79+
6680

6781
_MAPPINGS = [
6882
_SimpleBulkMapping(
@@ -75,6 +89,11 @@ def account_id(self, value):
7589
field_to_csv=lambda c: bulk_str(c.account_id),
7690
csv_to_field=lambda c, v: setattr(c, 'account_id', int(v) if v else None)
7791
),
92+
_SimpleBulkMapping(
93+
header=_StringTable.CampaignId,
94+
field_to_csv=lambda c: bulk_str(c.campaign_id),
95+
csv_to_field=lambda c, v: setattr(c, 'campaign_id', int(v) if v else None)
96+
),
7897
_SimpleBulkMapping(
7998
header=_StringTable.Status,
8099
field_to_csv=lambda c: c.status,

bingads/v13/bulk/entities/bulk_campaign.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
55
from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping, _ComplexBulkMapping
66
from bingads.v13.internal.extensions import *
7+
from decimal import Decimal
78

89
_DynamicFeedSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('DynamicFeedSetting'))
910
_TargetSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('TargetSetting'))
@@ -12,6 +13,7 @@
1213
_DisclaimerSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('DisclaimerSetting'))
1314
_VerifiedTrackingSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('VerifiedTrackingSetting'))
1415
_PerformanceMaxSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('PerformanceMaxSetting'))
16+
_NewCustomerAcquisitionGoalSetting = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('NewCustomerAcquisitionGoalSetting'))
1517

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

172+
def _get_new_customer_acquisition_goal_setting(self):
173+
return self._get_setting(_NewCustomerAcquisitionGoalSetting, 'NewCustomerAcquisitionGoalSetting')
174+
170175
def _get_setting(self, setting_type, setting_name):
171176
if not self.campaign.Settings.Setting:
172177
return None
@@ -205,6 +210,7 @@ def _read_campaign_type(c, v):
205210
if campaign_type.lower() == 'performancemax':
206211
BulkCampaign._create_campaign_setting(c.campaign, 'PerformanceMaxSetting')
207212
BulkCampaign._create_campaign_setting(c.campaign, 'ShoppingSetting')
213+
BulkCampaign._create_campaign_setting(c.campaign, 'NewCustomerAcquisitionGoalSetting')
208214

209215
@staticmethod
210216
def _create_campaign_setting(campaign, setting_type):
@@ -521,6 +527,72 @@ def _write_image_opt_out(c):
521527
return None
522528
return bulk_str(performance_max_setting.AutoGeneratedImageOptOut)
523529

530+
@staticmethod
531+
def _read_new_customer_acquisition_bid_only_mode(c, v):
532+
if not c.campaign.CampaignType:
533+
return None
534+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
535+
if 'performancemax' in campgaign_types:
536+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
537+
if not new_customer_acquisition_goal_setting:
538+
return None
539+
new_customer_acquisition_goal_setting.NewCustomerAcquisitionBidOnlyMode = parse_bool(v)
540+
541+
@staticmethod
542+
def _write_new_customer_acquisition_bid_only_mode(c):
543+
if not c.campaign.CampaignType:
544+
return None
545+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
546+
if 'performancemax' in campgaign_types:
547+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
548+
if not new_customer_acquisition_goal_setting:
549+
return None
550+
return bulk_str(new_customer_acquisition_goal_setting.NewCustomerAcquisitionBidOnlyMode)
551+
552+
@staticmethod
553+
def _read_new_customer_acquisition_goal_id(c, v):
554+
if not c.campaign.CampaignType:
555+
return None
556+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
557+
if 'performancemax' in campgaign_types:
558+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
559+
if not new_customer_acquisition_goal_setting:
560+
return None
561+
new_customer_acquisition_goal_setting.NewCustomerAcquisitionGoalId = int(v) if v else None
562+
563+
@staticmethod
564+
def _write_new_customer_acquisition_goal_id(c):
565+
if not c.campaign.CampaignType:
566+
return None
567+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
568+
if 'performancemax' in campgaign_types:
569+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
570+
if not new_customer_acquisition_goal_setting:
571+
return None
572+
return bulk_str(new_customer_acquisition_goal_setting.NewCustomerAcquisitionGoalId)
573+
574+
@staticmethod
575+
def _read_additional_conversion_value(c, v):
576+
if not c.campaign.CampaignType:
577+
return None
578+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
579+
if 'performancemax' in campgaign_types:
580+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
581+
if not new_customer_acquisition_goal_setting:
582+
return None
583+
new_customer_acquisition_goal_setting.AdditionalConversionValue = Decimal(v) if v else None
584+
585+
@staticmethod
586+
def _write_additional_conversion_value(c):
587+
if not c.campaign.CampaignType:
588+
return None
589+
campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType]
590+
if 'performancemax' in campgaign_types:
591+
new_customer_acquisition_goal_setting = c._get_new_customer_acquisition_goal_setting()
592+
if not new_customer_acquisition_goal_setting:
593+
return None
594+
return bulk_str(new_customer_acquisition_goal_setting.AdditionalConversionValue)
595+
524596
@staticmethod
525597
def _read_website(c, v):
526598
if not c.campaign.CampaignType:
@@ -756,6 +828,21 @@ def _write_website(c):
756828
field_to_csv=lambda c: field_to_csv_bool(c.should_serve_on_msan),
757829
csv_to_field=lambda c, v: setattr(c, 'should_serve_on_msan', parse_bool(v))
758830
),
831+
_SimpleBulkMapping(
832+
header=_StringTable.NewCustomerAcquisitionGoalId,
833+
field_to_csv=lambda c: BulkCampaign._write_new_customer_acquisition_goal_id(c),
834+
csv_to_field=lambda c, v: BulkCampaign._read_new_customer_acquisition_goal_id(c, v)
835+
),
836+
_SimpleBulkMapping(
837+
header=_StringTable.NewCustomerAcquisitionBidOnlyMode,
838+
field_to_csv=lambda c: BulkCampaign._write_new_customer_acquisition_bid_only_mode(c),
839+
csv_to_field=lambda c, v: BulkCampaign._read_new_customer_acquisition_bid_only_mode(c, v)
840+
),
841+
_SimpleBulkMapping(
842+
header=_StringTable.AdditionalConversionValue,
843+
field_to_csv=lambda c: BulkCampaign._write_additional_conversion_value(c),
844+
csv_to_field=lambda c, v: BulkCampaign._read_additional_conversion_value(c, v)
845+
),
759846
]
760847

761848
def read_additional_data(self, stream_reader):

bingads/v13/bulk/entities/bulk_campaign_conversion_goal.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class BulkCampaignConversionGoal(_SingleRecordBulkEntity):
1010
1111
Properties of this class and of classes that it is derived from, correspond to fields of the CampaignConversionGoal record in a bulk file.
1212
For more information, see CampaignConversionGoal at https://go.microsoft.com/fwlink/?linkid=846127
13-
13+
1414
*See also:*
1515
1616
* :class:`.BulkServiceManager`
@@ -19,10 +19,11 @@ class BulkCampaignConversionGoal(_SingleRecordBulkEntity):
1919
* :class:`.BulkFileWriter`
2020
"""
2121

22-
def __init__(self, campaign_conversion_goal = None):
22+
def __init__(self, campaign_conversion_goal = None, sub_type = None, action_type = None):
2323
super(BulkCampaignConversionGoal, self).__init__()
2424
self._campaign_conversion_goal = campaign_conversion_goal
25-
25+
self._sub_type = sub_type
26+
self._action_type = action_type
2627

2728
@property
2829
def campaign_conversion_goal(self):
@@ -34,7 +35,31 @@ def campaign_conversion_goal(self):
3435

3536
@campaign_conversion_goal.setter
3637
def campaign_conversion_goal(self, value):
37-
self._campaign_conversion_goal = value
38+
self._campaign_conversion_goal = value
39+
40+
@property
41+
def sub_type(self):
42+
""" Corresponds to the 'Sub Type' field in the bulk file.
43+
44+
:rtype: str
45+
"""
46+
return self._sub_type
47+
48+
@sub_type.setter
49+
def sub_type(self, value):
50+
self._sub_type = value
51+
52+
@property
53+
def action_type(self):
54+
""" Corresponds to the 'Action Type' field in the bulk file.
55+
56+
:rtype: str
57+
"""
58+
return self._action_type
59+
60+
@action_type.setter
61+
def action_type(self, value):
62+
self._action_type = value
3863

3964

4065
_MAPPINGS = [
@@ -48,6 +73,16 @@ def campaign_conversion_goal(self, value):
4873
field_to_csv=lambda c: bulk_str(c.campaign_conversion_goal.GoalId),
4974
csv_to_field=lambda c, v: setattr(c.campaign_conversion_goal, 'GoalId', int(v) if v else None)
5075
),
76+
_SimpleBulkMapping(
77+
header=_StringTable.ActionType,
78+
field_to_csv=lambda c: c.action_type,
79+
csv_to_field=lambda c, v: setattr(c, 'action_type', v)
80+
),
81+
_SimpleBulkMapping(
82+
header=_StringTable.SubType,
83+
field_to_csv=lambda c: c.sub_type,
84+
csv_to_field=lambda c, v: setattr(c, 'sub_type', v)
85+
),
5186
]
5287

5388
def process_mappings_from_row_values(self, row_values):
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V13
2+
from bingads.v13.internal.bulk.string_table import _StringTable
3+
from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
4+
from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
5+
from bingads.v13.internal.extensions import *
6+
from decimal import Decimal
7+
8+
9+
class BulkNewCustomerAcquisitionGoal (_SingleRecordBulkEntity):
10+
""" Represents a new customer acquisition goal that can be read or written in a bulk file.
11+
12+
Properties of this class and of classes that it is derived from, correspond to fields of the Budget record in a bulk file.
13+
For more information, see Budget at https://go.microsoft.com/fwlink/?linkid=846127
14+
15+
*See also:*
16+
17+
* :class:`.BulkServiceManager`
18+
* :class:`.BulkOperation`
19+
* :class:`.BulkFileReader`
20+
* :class:`.BulkFileWriter`
21+
"""
22+
23+
def __init__(self, new_customer_acquisition_goal=None, target=None):
24+
super(BulkNewCustomerAcquisitionGoal , self).__init__()
25+
self._new_customer_acquisition_goal = new_customer_acquisition_goal
26+
self._target = target
27+
28+
@property
29+
def new_customer_acquisition_goal (self):
30+
"""
31+
the NewCustomerAcquisitionGoal object, see more detail at: https://go.microsoft.com/fwlink/?linkid=846127
32+
"""
33+
return self._new_customer_acquisition_goal
34+
35+
@new_customer_acquisition_goal .setter
36+
def new_customer_acquisition_goal (self, value):
37+
self._new_customer_acquisition_goal = value
38+
39+
@property
40+
def target(self):
41+
"""
42+
The ids of audiences within the new customer acquisition.
43+
It should be split by simicolon. example: "123;456;789"
44+
Corresponds to 'Target' field in bulk file.
45+
:rtype: str
46+
"""
47+
return self._target
48+
49+
@target.setter
50+
def target(self, value):
51+
self._target = value
52+
53+
54+
_MAPPINGS = [
55+
_SimpleBulkMapping(
56+
header=_StringTable.Id,
57+
field_to_csv=lambda c: bulk_str(c.new_customer_acquisition_goal .Id),
58+
csv_to_field=lambda c, v: setattr(c.new_customer_acquisition_goal , 'Id', int(v) if v else None)
59+
),
60+
_SimpleBulkMapping(
61+
header=_StringTable.Target,
62+
field_to_csv=lambda c: bulk_str(c.target),
63+
csv_to_field=lambda c, v: setattr(c, 'target', v)
64+
),
65+
_SimpleBulkMapping(
66+
header=_StringTable.AdditionalConversionValue,
67+
field_to_csv=lambda c: bulk_str(c.new_customer_acquisition_goal.AdditionalValue),
68+
csv_to_field=lambda c, v: setattr(c.new_customer_acquisition_goal , 'AdditionalValue', Decimal(v) if v else None)
69+
),
70+
]
71+
72+
def process_mappings_from_row_values(self, row_values):
73+
self._new_customer_acquisition_goal = _CAMPAIGN_OBJECT_FACTORY_V13.create('NewCustomerAcquisitionGoal')
74+
row_values.convert_to_entity(self, BulkNewCustomerAcquisitionGoal ._MAPPINGS)
75+
76+
def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
77+
self._validate_property_not_null(self.new_customer_acquisition_goal , 'new_customer_acquisition_goal ')
78+
self.convert_to_values(row_values, BulkNewCustomerAcquisitionGoal ._MAPPINGS)
79+
80+
def read_additional_data(self, stream_reader):
81+
super(BulkNewCustomerAcquisitionGoal , self).read_additional_data(stream_reader)

bingads/v13/internal/bulk/bulk_object_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class _BulkObjectFactory():
233233
_StringTable.BrandItem: _EntityInfo(lambda: BulkBrandItem()),
234234
_StringTable.CampaignBrandList: _EntityInfo(lambda: BulkCampaignBrandListAssociation()),
235235
_StringTable.AssetGroupUrlTarget: _EntityInfo(lambda: BulkAssetGroupUrlTarget()),
236+
_StringTable.NewCustomerAcquisitionGoal: _EntityInfo(lambda: BulkNewCustomerAcquisitionGoal()),
236237
}
237238

238239
ADDITIONAL_OBJECT_MAP = {

bingads/v13/internal/bulk/csv_headers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class _CsvHeaders:
88
_StringTable.Status,
99
_StringTable.Id,
1010
_StringTable.ParentId,
11+
_StringTable.CampaignId,
1112
_StringTable.SubType,
1213
_StringTable.Campaign,
1314
_StringTable.AdGroup,
@@ -528,6 +529,12 @@ class _CsvHeaders:
528529
_StringTable.AssetGroupTargetValue1,
529530
_StringTable.AssetGroupTargetValue2,
530531
_StringTable.AssetGroupTargetValue3,
532+
533+
# New Customer Acquisition Goal
534+
_StringTable.AdditionalConversionValue,
535+
_StringTable.NewCustomerAcquisitionGoalId,
536+
_StringTable.NewCustomerAcquisitionBidOnlyMode,
537+
531538
]
532539

533540
@staticmethod

0 commit comments

Comments
 (0)