From 64bc0ed1440cce92a8191cb5750ce479a9939e7c Mon Sep 17 00:00:00 2001 From: Xinyu Wen Date: Mon, 25 Mar 2024 14:17:33 +0800 Subject: [PATCH] v13.0.19 --- HISTORY.rst | 9 + bingads/manifest.py | 2 +- bingads/v13/bulk/entities/__init__.py | 3 + .../bulk_account_negative_keyword_list.py | 164 ++++ bingads/v13/bulk/entities/bulk_campaign.py | 99 ++- .../v13/bulk/entities/bulk_data_exclusion.py | 95 ++ .../bulk/entities/bulk_negative_keywords.py | 29 +- .../entities/bulk_seasonality_adjustment.py | 102 +++ .../v13/internal/bulk/bulk_object_factory.py | 5 + bingads/v13/internal/bulk/csv_headers.py | 12 + bingads/v13/internal/bulk/string_table.py | 11 + bingads/v13/internal/extensions.py | 55 ++ .../proxies/production/adinsight_service.xml | 553 ++++++++++++ .../v13/proxies/production/bulk_service.xml | 84 ++ .../production/campaignmanagement_service.xml | 832 ++++++++++++++++++ .../proxies/production/reporting_service.xml | 2 + .../v13/proxies/sandbox/adinsight_service.xml | 553 ++++++++++++ bingads/v13/proxies/sandbox/bulk_service.xml | 84 ++ .../sandbox/campaignmanagement_service.xml | 804 +++++++++++++++++ .../v13/proxies/sandbox/reporting_service.xml | 2 + setup.py | 2 +- 21 files changed, 3487 insertions(+), 15 deletions(-) create mode 100644 bingads/v13/bulk/entities/bulk_account_negative_keyword_list.py create mode 100644 bingads/v13/bulk/entities/bulk_data_exclusion.py create mode 100644 bingads/v13/bulk/entities/bulk_seasonality_adjustment.py diff --git a/HISTORY.rst b/HISTORY.rst index 4fc6d232..e8342b70 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,15 @@ .. :changelog: Release History +13.0.19(2024-03-25) ++++++++++++++++++++++++++ +* 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 bulk mappings for Account Level Negative Keyword List i.e., BulkAccountNegativeKeywordList, BulkAccountNegativeKeywordListAssociation and BulkAccountSharedNegativeKeyword. +* Added bulk mappings for BulkSeasonalityAdjustment and BulkDataExclusion. +* Removed mappings for VerifiedTrackingSetting field in BulkCampaign. +* Added mappings for new field in BulkCampaign: AutoGeneratedImageOptOut and AutoGeneratedTextOptOut. +* Added PerformanceMaxsetting for PageFeedIds field in BulkCampaign. +* Added mappings for new BiddingScheme: CostPerSaleBiddingScheme. 13.0.18.1(2024-01-30) +++++++++++++++++++++++++ diff --git a/bingads/manifest.py b/bingads/manifest.py index 43f9e22c..55facdf3 100644 --- a/bingads/manifest.py +++ b/bingads/manifest.py @@ -1,5 +1,5 @@ import sys -VERSION = '13.0.18.1' +VERSION = '13.0.19' BULK_FORMAT_VERSION_6 = '6.0' WORKING_NAME = 'BingAdsSDKPython' USER_AGENT = '{0} {1} {2}'.format(WORKING_NAME, VERSION, sys.version_info[0:3]) diff --git a/bingads/v13/bulk/entities/__init__.py b/bingads/v13/bulk/entities/__init__.py index e466cd25..b9022fc6 100644 --- a/bingads/v13/bulk/entities/__init__.py +++ b/bingads/v13/bulk/entities/__init__.py @@ -47,3 +47,6 @@ from .bulk_asset_group_listing_group import * from .bulk_audience_group_asset_group_association import * from .bulk_campaign_negative_webpage import * +from .bulk_seasonality_adjustment import * +from .bulk_data_exclusion import * +from .bulk_account_negative_keyword_list import * diff --git a/bingads/v13/bulk/entities/bulk_account_negative_keyword_list.py b/bingads/v13/bulk/entities/bulk_account_negative_keyword_list.py new file mode 100644 index 00000000..f786f8c5 --- /dev/null +++ b/bingads/v13/bulk/entities/bulk_account_negative_keyword_list.py @@ -0,0 +1,164 @@ +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 bulk_str + +class BulkAccountNegativeKeywordList(_SingleRecordBulkEntity): + """ Represents an account negative keyword list association that can be read or written in a bulk file. + + This class exposes the :attr:`.BulkAccountNegativeKeywordList.account_negative_keyword_list` property that can be read and + written as fields of the account negative keyword list association record in a bulk file. + + For more information, see account negative keyword list association at https://go.microsoft.com/fwlink/?linkid=846127. + + *See also:* + + * :class:`.BulkServiceManager` + * :class:`.BulkOperation` + * :class:`.BulkFileReader` + * :class:`.BulkFileWriter` + """ + + def __init__(self, status=None, account_negative_keyword_list=None): + super(BulkAccountNegativeKeywordList, self).__init__() + + self._status = status + self._account_negative_keyword_list = account_negative_keyword_list + + @property + def account_negative_keyword_list(self): + """ The account negative keyword list association. + + see account negative keyword list association at https://go.microsoft.com/fwlink/?linkid=846127. + """ + + return self._account_negative_keyword_list + + @account_negative_keyword_list.setter + def account_negative_keyword_list(self, account_negative_keyword_list): + self._account_negative_keyword_list = account_negative_keyword_list + + @property + def status(self): + """ The status of the account negative keyword list association. + + :rtype: str + """ + + return self._status + + @status.setter + def status(self, status): + self._status = status + + _MAPPINGS = [ + _SimpleBulkMapping( + header=_StringTable.Id, + field_to_csv=lambda c: bulk_str(c.account_negative_keyword_list.Id), + csv_to_field=lambda c, v: setattr(c.account_negative_keyword_list, 'Id', int(v) if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.Status, + field_to_csv=lambda c: bulk_str(c.status), + csv_to_field=lambda c, v: setattr(c, 'status', v if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.Name, + field_to_csv=lambda c: c.account_negative_keyword_list.Name, + csv_to_field=lambda c, v: setattr(c.account_negative_keyword_list, 'Name', v) + ) + ] + + def process_mappings_to_row_values(self, row_values, exclude_readonly_data): + self._validate_property_not_null(self._account_negative_keyword_list, 'account_negative_keyword_list') + self.convert_to_values(row_values, BulkAccountNegativeKeywordList._MAPPINGS) + + def process_mappings_from_row_values(self, row_values): + self._account_negative_keyword_list = _CAMPAIGN_OBJECT_FACTORY_V13.create('AccountNegativeKeywordList') + self._account_negative_keyword_list.Type = 'AccountNegativeKeywordList' + row_values.convert_to_entity(self, BulkAccountNegativeKeywordList._MAPPINGS) + + def read_additional_data(self, stream_reader): + super(BulkAccountNegativeKeywordList, self).read_additional_data(stream_reader) + +class BulkAccountNegativeKeywordListAssociation(_SingleRecordBulkEntity): + """ Represents an account negative keyword list association that is assigned to a campaign. Each account negative keyword list association can be read or written in a bulk file. + + This class exposes the :attr:`BulkAccountNegativeKeywordListAssociation.SharedEntityAssociation` property that can be read + and written as fields of the account negative keyword list association record in a bulk file. + + For more information, see account negative keyword list association at https://go.microsoft.com/fwlink/?linkid=846127. + + *See also:* + + * :class:`.BulkServiceManager` + * :class:`.BulkOperation` + * :class:`.BulkFileReader` + * :class:`.BulkFileWriter` + """ + + def __init__(self, status=None, shared_entity_association=None): + super(BulkAccountNegativeKeywordListAssociation, self).__init__() + + self._shared_entity_association = shared_entity_association + self._status = status + + @property + def status(self): + """ The status of the account negative keyword list association. + + :rtype: str + """ + + return self._status + + @status.setter + def status(self, status): + self._status = status + + @property + def shared_entity_association(self): + """ The campaign and account negative keyword list association identifiers. + + see Campaign account negative keyword list association at https://go.microsoft.com/fwlink/?linkid=846127. + """ + + return self._shared_entity_association + + @shared_entity_association.setter + def shared_entity_association(self, shared_entity_association): + self._shared_entity_association = shared_entity_association + + _MAPPINGS = [ + _SimpleBulkMapping( + header=_StringTable.Status, + field_to_csv=lambda c: c.status, + csv_to_field=lambda c, v: setattr(c, 'status', v if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.Id, + field_to_csv=lambda c: bulk_str(c.shared_entity_association.SharedEntityId), + csv_to_field=lambda c, v: setattr(c.shared_entity_association, 'SharedEntityId', int(v)) + ), + _SimpleBulkMapping( + header=_StringTable.ParentId, + field_to_csv=lambda c: bulk_str(c.shared_entity_association.EntityId), + csv_to_field=lambda c, v: setattr(c.shared_entity_association, 'EntityId', int(v)) + ), + ] + + def process_mappings_to_row_values(self, row_values, exclude_readonly_data): + self._validate_property_not_null(self._shared_entity_association, 'shared_entity_association') + self.convert_to_values(row_values, BulkAccountNegativeKeywordListAssociation._MAPPINGS) + + def process_mappings_from_row_values(self, row_values): + self._shared_entity_association = _CAMPAIGN_OBJECT_FACTORY_V13.create('SharedEntityAssociation') + self._shared_entity_association.EntityType = 'Account' + self._shared_entity_association.SharedEntityType = 'NegativeKeywordList' + row_values.convert_to_entity(self, BulkAccountNegativeKeywordListAssociation._MAPPINGS) + + def read_additional_data(self, stream_reader): + super(BulkAccountNegativeKeywordListAssociation, self).read_additional_data(stream_reader) + + diff --git a/bingads/v13/bulk/entities/bulk_campaign.py b/bingads/v13/bulk/entities/bulk_campaign.py index 3ddc712a..7907b0a9 100644 --- a/bingads/v13/bulk/entities/bulk_campaign.py +++ b/bingads/v13/bulk/entities/bulk_campaign.py @@ -41,6 +41,7 @@ def __init__(self, account_id=None, campaign=None): self._verified_tracking_data = None self._destination_channel = None self._is_multi_channel_campaign = None + self._should_serve_on_msan = None @property def account_id(self): @@ -137,6 +138,14 @@ def is_multi_channel_campaign(self): def is_multi_channel_campaign(self, value): self._is_multi_channel_campaign = value + @property + def should_serve_on_msan(self): + return self._should_serve_on_msan + + @should_serve_on_msan.setter + def should_serve_on_msan(self, value): + self._should_serve_on_msan = value + def _get_dynamic_feed_setting(self): return self._get_setting(_DynamicFeedSetting, 'DynamicFeedSetting') @@ -419,20 +428,76 @@ def _read_page_feed_ids(c, v): if not c.campaign.CampaignType: return None campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType] - dsa_setting = c._get_dsa_setting() - if not dsa_setting: - return None - dsa_setting.PageFeedIds.long = csv_to_field_PageFeedIds(v) + if 'performancemax' in campgaign_types: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + performance_max_setting.PageFeedIds.long = csv_to_field_PageFeedIds(v) + else: + dsa_setting = c._get_dsa_setting() + if not dsa_setting: + return None + dsa_setting.PageFeedIds.long = csv_to_field_PageFeedIds(v) @staticmethod def _write_page_feed_ids(c): if not c.campaign.CampaignType: return None campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType] - dsa_setting = c._get_dsa_setting() - if not dsa_setting: + if 'performancemax' in campgaign_types: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + return field_to_csv_Ids(performance_max_setting.PageFeedIds, c.campaign.Id) + else: + dsa_setting = c._get_dsa_setting() + if not dsa_setting: + return None + return field_to_csv_Ids(dsa_setting.PageFeedIds, c.campaign.Id) + + @staticmethod + def _read_text_opt_out(c, v): + if not c.campaign.CampaignType: return None - return field_to_csv_Ids(dsa_setting.PageFeedIds, c.campaign.Id) + campgaign_types = [campaign_type.lower() for campaign_type in c.campaign.CampaignType] + if 'performancemax' in campgaign_types: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + performance_max_setting.AutoGeneratedTextOptOut = parse_bool(v) + + @staticmethod + def _write_text_opt_out(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: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + return bulk_str(performance_max_setting.AutoGeneratedTextOptOut) + + @staticmethod + def _read_image_opt_out(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: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + performance_max_setting.AutoGeneratedImageOptOut = parse_bool(v) + + @staticmethod + def _write_image_opt_out(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: + performance_max_setting = c._get_performance_max_setting() + if not performance_max_setting: + return None + return bulk_str(performance_max_setting.AutoGeneratedImageOptOut) @staticmethod def _read_website(c, v): @@ -639,11 +704,6 @@ def _write_website(c): field_to_csv=lambda c: BulkCampaign._write_DynamicDescriptionEnabled(c), csv_to_field=lambda c, v: BulkCampaign._read_DynamicDescriptionEnabled(c, v) ), - _SimpleBulkMapping( - header=_StringTable.Details, - field_to_csv=lambda c: to_verified_tracking_setting_string(c.verified_tracking_data), - csv_to_field=lambda c, v: setattr(c, 'verified_tracking_data', parse_verified_tracking_setting(v) if v else None) - ), _SimpleBulkMapping( header=_StringTable.DestinationChannel, field_to_csv=lambda c: c.destination_channel, @@ -654,6 +714,21 @@ def _write_website(c): field_to_csv=lambda c: field_to_csv_bool(c.is_multi_channel_campaign), csv_to_field=lambda c, v: setattr(c, 'is_multi_channel_campaign', parse_bool(v)) ), + _SimpleBulkMapping( + header=_StringTable.AutoGeneratedTextOptOut, + field_to_csv=lambda c: BulkCampaign._write_text_opt_out(c), + csv_to_field=lambda c, v: BulkCampaign._read_text_opt_out(c, v) + ), + _SimpleBulkMapping( + header=_StringTable.AutoGeneratedImageOptOut, + field_to_csv=lambda c: BulkCampaign._write_image_opt_out(c), + csv_to_field=lambda c, v: BulkCampaign._read_image_opt_out(c, v) + ), + _SimpleBulkMapping( + header=_StringTable.ShouldServeOnMSAN, + 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)) + ), ] def read_additional_data(self, stream_reader): diff --git a/bingads/v13/bulk/entities/bulk_data_exclusion.py b/bingads/v13/bulk/entities/bulk_data_exclusion.py new file mode 100644 index 00000000..b55276d6 --- /dev/null +++ b/bingads/v13/bulk/entities/bulk_data_exclusion.py @@ -0,0 +1,95 @@ +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 * + +class BulkDataExclusion(_SingleRecordBulkEntity): + """ Represents an data exclusion. + + This class exposes the property :attr:`data_exclusion` that can be read and written as fields of the data exclusion record + in a bulk file. + + For more information, see data exclusion at https://go.microsoft.com/fwlink/?linkid=846127. + + *See also:* + + * :class:`.BulkServiceManager` + * :class:`.BulkOperation` + * :class:`.BulkFileReader` + * :class:`.BulkFileWriter` + """ + + def __init__(self, campaign_id=None, campaign_name=None, data_exclusion=None): + super(BulkDataExclusion, self).__init__() + + self._data_exclusion = data_exclusion + + @property + def data_exclusion(self): + """ The DataExclusion Data Object of the Campaign Management Service. + + A subset of DataExclusion properties are available in the Ad Group record. + For more information, see Ad Group at https://go.microsoft.com/fwlink/?linkid=846127. + """ + return self._data_exclusion + + @data_exclusion.setter + def data_exclusion(self, data_exclusion): + self._data_exclusion = data_exclusion + + _MAPPINGS = [ + _SimpleBulkMapping( + header=_StringTable.Id, + field_to_csv=lambda c: bulk_str(c.data_exclusion.Id), + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'Id', int(v) if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.DataExclusion, + field_to_csv=lambda c: bulk_str(c.data_exclusion.Name), + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'Name', v) + ), + _SimpleBulkMapping( + header=_StringTable.StartDate, + field_to_csv=lambda c: bulk_datetime_str2(c.data_exclusion.StartDate), + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'StartDate', parse_datetime2(v)) + ), + _SimpleBulkMapping( + header=_StringTable.EndDate, + field_to_csv=lambda c: bulk_datetime_str2(c.data_exclusion.EndDate), + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'EndDate', parse_datetime2(v)) + ), + _SimpleBulkMapping( + header=_StringTable.Description, + field_to_csv=lambda c: c.data_exclusion.Description, + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'Description', v) + ), + _SimpleBulkMapping( + header=_StringTable.CampaignType, + field_to_csv=lambda c: field_to_csv_CampaignType(c.data_exclusion), + csv_to_field=lambda c, v: csv_to_field_CampaignType(c.data_exclusion, v) + ), + _SimpleBulkMapping( + header=_StringTable.DeviceType, + field_to_csv=lambda c: bulk_str(c.data_exclusion.DeviceTypeFilter), + csv_to_field=lambda c, v: setattr(c.data_exclusion, 'DeviceTypeFilter', v) + ), + _SimpleBulkMapping( + header=_StringTable.CampaignAssociations, + field_to_csv=lambda c: field_to_csv_CampaignAssociations(c.data_exclusion), + csv_to_field=lambda c, v: csv_to_field_CampaignAssociations(c.data_exclusion, v) + ), + ] + + def process_mappings_from_row_values(self, row_values): + self.data_exclusion = _CAMPAIGN_OBJECT_FACTORY_V13.create('DataExclusion') + + row_values.convert_to_entity(self, BulkDataExclusion._MAPPINGS) + + def process_mappings_to_row_values(self, row_values, exclude_readonly_data): + self._validate_property_not_null(self._data_exclusion, 'DataExclusion') + self.convert_to_values(row_values, BulkDataExclusion._MAPPINGS) + + def read_additional_data(self, stream_reader): + super(BulkDataExclusion, self).read_additional_data(stream_reader) diff --git a/bingads/v13/bulk/entities/bulk_negative_keywords.py b/bingads/v13/bulk/entities/bulk_negative_keywords.py index a20bceb3..bce51892 100644 --- a/bingads/v13/bulk/entities/bulk_negative_keywords.py +++ b/bingads/v13/bulk/entities/bulk_negative_keywords.py @@ -373,7 +373,6 @@ def process_mappings_from_row_values(self, row_values): def read_additional_data(self, stream_reader): super(BulkCampaignNegativeKeywordList, self).read_additional_data(stream_reader) - class BulkNegativeKeywordList(_SingleRecordBulkEntity): """ Represents a negative keyword list that can be read or written in a bulk file. @@ -480,3 +479,31 @@ def negative_keyword_list_id(self): @negative_keyword_list_id.setter def negative_keyword_list_id(self, value): self._parent_id = value + +class BulkAccountSharedNegativeKeyword(_BulkNegativeKeyword): + """ Represents an account negative keyword that is shared in a negative keyword list. + + Each shared negative keyword can be read or written in a bulk file. + This class exposes the :attr:`.BulkNegativeKeyword.NegativeKeyword` property that + can be read and written as fields of the Account Shared Negative Keyword record in a bulk file. + + For more information, see Account Shared Negative Keyword at https://go.microsoft.com/fwlink/?linkid=846127. + + *See also:* + + * :class:`.BulkServiceManager` + * :class:`.BulkOperation` + * :class:`.BulkFileReader` + * :class:`.BulkFileWriter` + """ + + def __init__(self, status=None, negative_keyword=None, negative_keyword_list_id=None): + super(BulkAccountSharedNegativeKeyword, self).__init__(status, negative_keyword, negative_keyword_list_id) + + @property + def negative_keyword_list_id(self): + return self._parent_id + + @negative_keyword_list_id.setter + def negative_keyword_list_id(self, value): + self._parent_id = value diff --git a/bingads/v13/bulk/entities/bulk_seasonality_adjustment.py b/bingads/v13/bulk/entities/bulk_seasonality_adjustment.py new file mode 100644 index 00000000..111148ba --- /dev/null +++ b/bingads/v13/bulk/entities/bulk_seasonality_adjustment.py @@ -0,0 +1,102 @@ +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 * + +class BulkSeasonalityAdjustment(_SingleRecordBulkEntity): + """ Represents an seasonality adjustment. + + This class exposes the property :attr:`seasonality_adjustment` that can be read and written as fields of the seasonality adjustment record + in a bulk file. + + For more information, see seasonality adjustment at https://go.microsoft.com/fwlink/?linkid=846127. + + *See also:* + + * :class:`.BulkServiceManager` + * :class:`.BulkOperation` + * :class:`.BulkFileReader` + * :class:`.BulkFileWriter` + """ + + def __init__(self, campaign_id=None, campaign_name=None, seasonality_adjustment=None): + super(BulkSeasonalityAdjustment, self).__init__() + + self._seasonality_adjustment = seasonality_adjustment + + @property + def seasonality_adjustment(self): + """ The SeasonalityAdjustment Data Object of the Campaign Management Service. + + A subset of SeasonalityAdjustment properties are available in the Ad Group record. + For more information, see Ad Group at https://go.microsoft.com/fwlink/?linkid=846127. + """ + return self._seasonality_adjustment + + @seasonality_adjustment.setter + def seasonality_adjustment(self, seasonality_adjustment): + self._seasonality_adjustment = seasonality_adjustment + + + + _MAPPINGS = [ + _SimpleBulkMapping( + header=_StringTable.Id, + field_to_csv=lambda c: bulk_str(c.seasonality_adjustment.Id), + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'Id', int(v) if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.SeasonalityAdjustment, + field_to_csv=lambda c: bulk_str(c.seasonality_adjustment.Name), + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'Name', v) + ), + _SimpleBulkMapping( + header=_StringTable.StartDate, + field_to_csv=lambda c: bulk_datetime_str2(c.seasonality_adjustment.StartDate), + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'StartDate', parse_datetime2(v)) + ), + _SimpleBulkMapping( + header=_StringTable.EndDate, + field_to_csv=lambda c: bulk_datetime_str2(c.seasonality_adjustment.EndDate), + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'EndDate', parse_datetime2(v)) + ), + _SimpleBulkMapping( + header=_StringTable.Description, + field_to_csv=lambda c: c.seasonality_adjustment.Description, + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'Description', v) + ), + _SimpleBulkMapping( + header=_StringTable.CampaignType, + field_to_csv=lambda c: field_to_csv_CampaignType(c.seasonality_adjustment), + csv_to_field=lambda c, v: csv_to_field_CampaignType(c.seasonality_adjustment, v) + ), + _SimpleBulkMapping( + header=_StringTable.DeviceType, + field_to_csv=lambda c: bulk_str(c.seasonality_adjustment.DeviceTypeFilter), + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'DeviceTypeFilter', v) + ), + _SimpleBulkMapping( + header=_StringTable.AdjustmentValue, + field_to_csv=lambda c: c.seasonality_adjustment.AdjustmentPercentage, + csv_to_field=lambda c, v: setattr(c.seasonality_adjustment, 'AdjustmentPercentage', float(v) if v else None) + ), + _SimpleBulkMapping( + header=_StringTable.CampaignAssociations, + field_to_csv=lambda c: field_to_csv_CampaignAssociations(c.seasonality_adjustment), + csv_to_field=lambda c, v: csv_to_field_CampaignAssociations(c.seasonality_adjustment, v) + ), + ] + + def process_mappings_from_row_values(self, row_values): + self.seasonality_adjustment = _CAMPAIGN_OBJECT_FACTORY_V13.create('SeasonalityAdjustment') + + row_values.convert_to_entity(self, BulkSeasonalityAdjustment._MAPPINGS) + + def process_mappings_to_row_values(self, row_values, exclude_readonly_data): + self._validate_property_not_null(self._seasonality_adjustment, 'SeasonalityAdjustment') + self.convert_to_values(row_values, BulkSeasonalityAdjustment._MAPPINGS) + + def read_additional_data(self, stream_reader): + super(BulkSeasonalityAdjustment, self).read_additional_data(stream_reader) diff --git a/bingads/v13/internal/bulk/bulk_object_factory.py b/bingads/v13/internal/bulk/bulk_object_factory.py index 837804ae..b3d925da 100644 --- a/bingads/v13/internal/bulk/bulk_object_factory.py +++ b/bingads/v13/internal/bulk/bulk_object_factory.py @@ -209,6 +209,11 @@ class _BulkObjectFactory(): _StringTable.CampaignNegativeWebpage: _EntityInfo(lambda: BulkCampaignNegativeWebpage()), _StringTable.AssetGroupListingGroup: _EntityInfo(lambda: BulkAssetGroupListingGroup()), _StringTable.AudienceGroupAssetGroupAssociation: _EntityInfo(lambda: BulkAudienceGroupAssetGroupAssociation()), + _StringTable.SeasonalityAdjustment: _EntityInfo(lambda: BulkSeasonalityAdjustment()), + _StringTable.DataExclusion: _EntityInfo(lambda: BulkDataExclusion()), + 'Account Negative Keyword List': _EntityInfo(lambda: BulkAccountNegativeKeywordList()), + 'Account Negative Keyword List Association': _EntityInfo(lambda: BulkAccountNegativeKeywordListAssociation()), + 'Account Shared Negative Keyword': _EntityInfo(lambda: BulkAccountSharedNegativeKeyword()), } ADDITIONAL_OBJECT_MAP = { diff --git a/bingads/v13/internal/bulk/csv_headers.py b/bingads/v13/internal/bulk/csv_headers.py index 2a8b96e1..0fca20f9 100644 --- a/bingads/v13/internal/bulk/csv_headers.py +++ b/bingads/v13/internal/bulk/csv_headers.py @@ -328,6 +328,7 @@ class _CsvHeaders: _StringTable.BidStrategyTargetImpressionShare, _StringTable.BidStrategyCommissionRate, _StringTable.BidStrategyPercentMaxCpc, + _StringTable.BidStrategyTargetCostPerSale, # Ad Format Preference _StringTable.AdFormatPreference, @@ -469,6 +470,17 @@ class _CsvHeaders: _StringTable.CampaignNegativeWebpage, _StringTable.AssetGroupListingGroup, _StringTable.AudienceGroupAssetGroupAssociation, + _StringTable.AutoGeneratedTextOptOut, + _StringTable.AutoGeneratedImageOptOut, + + # Seasonality Adjustment + _StringTable.SeasonalityAdjustment, + _StringTable.DataExclusion, + _StringTable.DeviceType, + _StringTable.CampaignAssociations, + + # DNV Serving on MSAN + _StringTable.ShouldServeOnMSAN, ] @staticmethod diff --git a/bingads/v13/internal/bulk/string_table.py b/bingads/v13/internal/bulk/string_table.py index 44c75f93..60c58410 100644 --- a/bingads/v13/internal/bulk/string_table.py +++ b/bingads/v13/internal/bulk/string_table.py @@ -435,6 +435,7 @@ class _StringTable: BidStrategyTargetImpressionShare = "Bid Strategy TargetImpressionShare" BidStrategyPercentMaxCpc = "Bid Strategy PercentMaxCpc" BidStrategyCommissionRate = "Bid Strategy CommissionRate" + BidStrategyTargetCostPerSale = "Bid Strategy TargetCostPerSale" # Remarketing Audience = "Audience" @@ -647,8 +648,18 @@ class _StringTable: AgeRanges = "Age Ranges" GenderTypes = "Gender Types" ParentListingGroupId = "Parent Listing Group Id" + AutoGeneratedTextOptOut = "Auto Generated Text Assets Opt Out" + AutoGeneratedImageOptOut = "Auto Generated Image Assets Opt Out" # MultiChannel Campaign DestinationChannel = "Destination Channel" IsMultiChannelCampaign = "Is Multi Channel Campaign" + # Seasonality Adjustment + SeasonalityAdjustment = "Seasonality Adjustment" + DataExclusion = "Data Exclusion" + DeviceType = "Device Type" + CampaignAssociations = "Campaign Associations" + + # DNV Serving on MSAN + ShouldServeOnMSAN = "Should Serve On MSAN" diff --git a/bingads/v13/internal/extensions.py b/bingads/v13/internal/extensions.py index 82f95bfc..228587e5 100644 --- a/bingads/v13/internal/extensions.py +++ b/bingads/v13/internal/extensions.py @@ -55,6 +55,7 @@ TextAsset_Type = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('TextAsset')) ImageAsset_Type = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('ImageAsset')) VideoAsset_Type = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('VideoAsset')) +CampaignAssociation = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('CampaignAssociation')) KeyValuePairOfstringstring = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('ns1:KeyValuePairOfstringstring')) ArrayOfKeyValuePairOfstringstring = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('ns1:ArrayOfKeyValuePairOfstringstring')) ArrayOfArrayOfKeyValuePairOfstringstring = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('ns1:ArrayOfArrayOfKeyValuePairOfstringstring')) @@ -188,6 +189,9 @@ def entity_csv_to_biddingscheme(row_values, entity): success, target_ad_position_value = row_values.try_get_value(_StringTable.BidStrategyTargetAdPosition) + success, target_cost_per_sale_row_value = row_values.try_get_value(_StringTable.BidStrategyTargetCostPerSale) + target_cost_per_sale_value = float(target_cost_per_sale_row_value) if target_cost_per_sale_row_value else None + if bid_strategy_type == 'MaxConversions': entity.BiddingScheme.MaxCpc = max_cpc_value entity.BiddingScheme.TargetCpa = target_cpa_value @@ -217,6 +221,9 @@ def entity_csv_to_biddingscheme(row_values, entity): elif bid_strategy_type == "Commission": entity.BiddingScheme.MaxPercentCpc = commission_rate_value entity.BiddingScheme.Type = "Commission" + elif bid_strategy_type == "CostPerSale": + entity.BiddingScheme.TargetCostPerSale = target_cost_per_sale_value + entity.BiddingScheme.Type = "CostPerSale" def bid_strategy_biddingscheme_to_csv(bulk_bid_strategy, row_values): entity_biddingscheme_to_csv(bulk_bid_strategy.bid_strategy, row_values) @@ -256,6 +263,8 @@ def entity_biddingscheme_to_csv(entity, row_values): row_values[_StringTable.BidStrategyPercentMaxCpc] = bulk_str(entity.BiddingScheme.MaxPercentCpc) elif bid_strategy_type == 'Commission': row_values[_StringTable.BidStrategyCommissionRate] = bulk_str(entity.BiddingScheme.CommissionRate) + elif bid_strategy_type == 'CostPerSale': + row_values[_StringTable.BidStrategyTargetCostPerSale] = bulk_str(entity.BiddingScheme.TargetCostPerSale) def bulk_optional_str(value, id): @@ -358,6 +367,37 @@ def csv_to_field_GenderTypes(entity, value): return entity.gender_types = [None if i == 'None' else i for i in value.split(';')] +def field_to_csv_CampaignType(entity): + campaign_type = entity.CampaignTypeFilter + if campaign_type is None or len(campaign_type) == 0: + return None + return ','.join(type for type in campaign_type) + +def csv_to_field_CampaignType(entity, value): + if value is None or value.strip() == '': + return + entity.CampaignTypeFilter = [None if i == 'None' else i for i in value.split(',')] + +def field_to_csv_CampaignAssociations(entity): + associations = entity.CampaignAssociations + if associations is None or len(associations.CampaignAssociation) == 0: + return None + result = "" + for association in associations.CampaignAssociation: + result += str(association.CampaignId) + ";" + return result[:-1] + +def csv_to_field_CampaignAssociations(entity, value): + if value is None or value.strip() == '': + return + result = [] + strs = value.split(';') + for str in strs: + association = CampaignAssociation() + association.CampaignId = int(str) + result.append(association) + entity.CampaignAssociations = result + def field_to_csv_MediaIds(entity): """ MediaIds field to csv content @@ -2027,3 +2067,18 @@ def to_operation(op): if op.lower() == 'or': return 'Or' if op.lower() == 'not': return 'Not' return none + +def bulk_datetime_str2(value): + if value is None: + return None + + return value.strftime('%Y/%m/%d %H:%M:%S') + +def parse_datetime2(value): + + if not value: + return None + try: + return datetime.strptime(value, '%Y/%m/%d %H:%M:%S') + except Exception: + return parse_datetime(value) diff --git a/bingads/v13/proxies/production/adinsight_service.xml b/bingads/v13/proxies/production/adinsight_service.xml index f1ac8dc9..f1cc7426 100644 --- a/bingads/v13/proxies/production/adinsight_service.xml +++ b/bingads/v13/proxies/production/adinsight_service.xml @@ -3246,6 +3246,506 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 23 + + + + + + + 15 + + + + + + + 1 + + + + + + + 78 + + + + + + + 87 + + + + + + + 2 + + + + + + + 3 + + + + + + + 16 + + + + + + + 18 + + + + + + + 20 + + + + + + + 5 + + + + + + + 88 + + + + + + + 25 + + + + + + + 6 + + + + + + + 33 + + + + + + + 30 + + + + + + + 36 + + + + + + + 8 + + + + + + + 48 + + + + + + + 58 + + + + + + + 57 + + + + + + + 52 + + + + + + + 82 + + + + + + + 10 + + + + + + + 9 + + + + + + + 64 + + + + + + + 65 + + + + + + + 69 + + + + + + + 34 + + + + + + + 72 + + + + + + + 74 + + + + + + + 13 + + + + + + + 11 + + + + + + + 4 + + + + + + + 93 + + + + + + + 7 + + + + + + + 12 + + + + + + + 45 + + + + + + + 17 + + + + + + + 67 + + + + + + + 21 + + + + + + + 35 + + + + + + + 99 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4080,6 +4580,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -4267,6 +4791,12 @@ + + + + + + @@ -4984,6 +5514,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bingads/v13/proxies/production/bulk_service.xml b/bingads/v13/proxies/production/bulk_service.xml index 5cc722a2..fad72b2e 100644 --- a/bingads/v13/proxies/production/bulk_service.xml +++ b/bingads/v13/proxies/production/bulk_service.xml @@ -1191,6 +1191,90 @@ + + + + 161 + + + + + + + 162 + + + + + + + 163 + + + + + + + 164 + + + + + + + 165 + + + + + + + 166 + + + + + + + 167 + + + + + + + 168 + + + + + + + 169 + + + + + + + 170 + + + + + + + 171 + + + + + + + 172 + + + diff --git a/bingads/v13/proxies/production/campaignmanagement_service.xml b/bingads/v13/proxies/production/campaignmanagement_service.xml index c4bfb83d..a3711e86 100644 --- a/bingads/v13/proxies/production/campaignmanagement_service.xml +++ b/bingads/v13/proxies/production/campaignmanagement_service.xml @@ -947,6 +947,20 @@ + + + + + + + + + + + + + + @@ -1394,6 +1408,7 @@ + @@ -4766,6 +4781,16 @@ + + + + + + + + + + @@ -4881,6 +4906,14 @@ + + + + + + + + @@ -7286,6 +7319,13 @@ + + + + + + + @@ -7377,6 +7417,20 @@ + + + + + + + + + + + + + + @@ -7643,6 +7697,27 @@ + + + + 32768 + + + + + + + 65536 + + + + + + + 131072 + + + @@ -7887,6 +7962,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11471,6 +11773,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12336,6 +12878,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15652,6 +16254,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bingads/v13/proxies/production/reporting_service.xml b/bingads/v13/proxies/production/reporting_service.xml index a6162b12..fd612003 100644 --- a/bingads/v13/proxies/production/reporting_service.xml +++ b/bingads/v13/proxies/production/reporting_service.xml @@ -4113,6 +4113,7 @@ + @@ -4195,6 +4196,7 @@ + diff --git a/bingads/v13/proxies/sandbox/adinsight_service.xml b/bingads/v13/proxies/sandbox/adinsight_service.xml index 19468a03..a85e68f5 100644 --- a/bingads/v13/proxies/sandbox/adinsight_service.xml +++ b/bingads/v13/proxies/sandbox/adinsight_service.xml @@ -3246,6 +3246,506 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 23 + + + + + + + 15 + + + + + + + 1 + + + + + + + 78 + + + + + + + 87 + + + + + + + 2 + + + + + + + 3 + + + + + + + 16 + + + + + + + 18 + + + + + + + 20 + + + + + + + 5 + + + + + + + 88 + + + + + + + 25 + + + + + + + 6 + + + + + + + 33 + + + + + + + 30 + + + + + + + 36 + + + + + + + 8 + + + + + + + 48 + + + + + + + 58 + + + + + + + 57 + + + + + + + 52 + + + + + + + 82 + + + + + + + 10 + + + + + + + 9 + + + + + + + 64 + + + + + + + 65 + + + + + + + 69 + + + + + + + 34 + + + + + + + 72 + + + + + + + 74 + + + + + + + 13 + + + + + + + 11 + + + + + + + 4 + + + + + + + 93 + + + + + + + 7 + + + + + + + 12 + + + + + + + 45 + + + + + + + 17 + + + + + + + 67 + + + + + + + 21 + + + + + + + 35 + + + + + + + 99 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4080,6 +4580,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -4267,6 +4791,12 @@ + + + + + + @@ -4984,6 +5514,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bingads/v13/proxies/sandbox/bulk_service.xml b/bingads/v13/proxies/sandbox/bulk_service.xml index 8ba6e837..cc383e37 100644 --- a/bingads/v13/proxies/sandbox/bulk_service.xml +++ b/bingads/v13/proxies/sandbox/bulk_service.xml @@ -1191,6 +1191,90 @@ + + + + 161 + + + + + + + 162 + + + + + + + 163 + + + + + + + 164 + + + + + + + 165 + + + + + + + 166 + + + + + + + 167 + + + + + + + 168 + + + + + + + 169 + + + + + + + 170 + + + + + + + 171 + + + + + + + 172 + + + diff --git a/bingads/v13/proxies/sandbox/campaignmanagement_service.xml b/bingads/v13/proxies/sandbox/campaignmanagement_service.xml index 612c5333..4054fabf 100644 --- a/bingads/v13/proxies/sandbox/campaignmanagement_service.xml +++ b/bingads/v13/proxies/sandbox/campaignmanagement_service.xml @@ -947,6 +947,20 @@ + + + + + + + + + + + + + + @@ -1394,6 +1408,7 @@ + @@ -4766,6 +4781,16 @@ + + + + + + + + + + @@ -4881,6 +4906,14 @@ + + + + + + + + @@ -7391,6 +7424,13 @@ + + + + + + + @@ -7671,6 +7711,13 @@ + + + + 131072 + + + @@ -7915,6 +7962,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11499,6 +11773,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12364,6 +12878,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15680,6 +16254,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bingads/v13/proxies/sandbox/reporting_service.xml b/bingads/v13/proxies/sandbox/reporting_service.xml index c82f45f9..4b5a9a0b 100644 --- a/bingads/v13/proxies/sandbox/reporting_service.xml +++ b/bingads/v13/proxies/sandbox/reporting_service.xml @@ -4113,6 +4113,7 @@ + @@ -4195,6 +4196,7 @@ + diff --git a/setup.py b/setup.py index 6dbf0672..88f52c54 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ except ImportError: from distutils.core import setup -VERSION = '13.0.18.1' +VERSION = '13.0.19' with open('README.rst', 'r') as f: readme = f.read()