diff --git a/HISTORY.rst b/HISTORY.rst
index ab20460a..d4a2737f 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,9 +1,15 @@
.. :changelog:
Release History
+12.13.5(2019-09-12)
++++++++++++++++++++++++++
+* Map the Bid Adjustment column to a BidMultiplier via BulkAdGroupProductPartition.
+* Updated Bing Ads API version 12 and 13 service proxies to reflect recent interface changes. For more information please see the Bing Ads API Release Notes: https://docs.microsoft.com/en-us/advertising/guides/release-notes.
+
+
12.13.4.1(2019-08-23)
+++++++++++++++++++++++++
-* Write TextAsset and ImageAsset to the Bulk upload file without the Type explicitly set.
+* Write TextAsset and ImageAsset to the Bulk upload file without the Type explicitly set.
12.13.4(2019-08-09)
+++++++++++++++++++++++++
diff --git a/bingads/manifest.py b/bingads/manifest.py
index 88787d96..ee303345 100644
--- a/bingads/manifest.py
+++ b/bingads/manifest.py
@@ -1,5 +1,5 @@
import sys
-VERSION = '12.13.4.1'
+VERSION = '12.13.5'
BULK_FORMAT_VERSION_5 = '5.0'
BULK_FORMAT_VERSION_6 = '6.0'
WORKING_NAME = 'BingAdsSDKPython'
diff --git a/bingads/v12/bulk/entities/bulk_ad_group_product_partition.py b/bingads/v12/bulk/entities/bulk_ad_group_product_partition.py
index 1b2e52dc..fb8c182f 100644
--- a/bingads/v12/bulk/entities/bulk_ad_group_product_partition.py
+++ b/bingads/v12/bulk/entities/bulk_ad_group_product_partition.py
@@ -1,7 +1,7 @@
from bingads.v12.bulk.entities import *
from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V12
from bingads.v12.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
-from bingads.v12.internal.bulk.mappings import _SimpleBulkMapping
+from bingads.v12.internal.bulk.mappings import _SimpleBulkMapping, _ComplexBulkMapping
from bingads.v12.internal.bulk.string_table import _StringTable
from bingads.v12.bulk.entities.common import PerformanceData
# from bingads.v12.internal.extensions import bulk_str
@@ -9,7 +9,67 @@
_BiddableAdGroupCriterion = type(_CAMPAIGN_OBJECT_FACTORY_V12.create('BiddableAdGroupCriterion'))
_NegativeAdGroupCriterion = type(_CAMPAIGN_OBJECT_FACTORY_V12.create('NegativeAdGroupCriterion'))
-
+_FixedBid = type(_CAMPAIGN_OBJECT_FACTORY_V12.create('FixedBid'))
+
+def csv_to_bidding(row_values, entity):
+ success, exclude = row_values.try_get_value(_StringTable.IsExcluded)
+ if exclude is None:
+ exclude = ''
+ exclude = exclude.lower()
+ if exclude == 'yes' or exclude == 'true':
+ is_excluded = True
+ elif exclude == 'no' or exclude == 'false':
+ is_excluded = False
+ else:
+ raise ValueError('IsExcluded can only be set to TRUE|FALSE in Ad Group Product Partition row')
+ if is_excluded:
+ product_partition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductPartition')
+ product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductCondition')
+ product_partition.Type = 'ProductPartition'
+
+ negative_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V12.create('NegativeAdGroupCriterion')
+ negative_ad_group_criterion.Criterion = product_partition
+ negative_ad_group_criterion.Type = 'NegativeAdGroupCriterion'
+
+ entity.ad_group_criterion = negative_ad_group_criterion
+ else:
+ product_partition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductPartition')
+ product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductCondition')
+ product_partition.Type = 'ProductPartition'
+
+ bid = _CAMPAIGN_OBJECT_FACTORY_V12.create('FixedBid')
+ bid.Type = 'FixedBid'
+
+ biddable_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V12.create('BiddableAdGroupCriterion')
+ biddable_ad_group_criterion.Criterion = product_partition
+
+ success, bid_value = row_values.try_get_value(_StringTable.Bid)
+ if success and bid_value is not None and bid_value != '':
+ bid.Amount = float(bid_value)
+ else:
+ success, bid_value = row_values.try_get_value(_StringTable.BidAdjustment)
+ if success and bid_value is not None and bid_value != '':
+ bid = _CAMPAIGN_OBJECT_FACTORY_V12.create('BidMultiplier')
+ bid.Type = 'BidMultiplier'
+ bid.Multiplier = float(bid_value)
+
+ biddable_ad_group_criterion.CriterionBid = bid
+ biddable_ad_group_criterion.Type = 'BiddableAdGroupCriterion'
+
+ entity.ad_group_criterion = biddable_ad_group_criterion
+
+def bidding_to_csv(entity, row_values):
+ if isinstance(entity.ad_group_criterion, _NegativeAdGroupCriterion):
+ row_values[_StringTable.IsExcluded] = 'True'
+ else:
+ row_values[_StringTable.IsExcluded] = 'False'
+ bid = entity.ad_group_criterion.CriterionBid
+ if bid is None:
+ return
+ if isinstance(bid, _FixedBid):
+ row_values[_StringTable.Bid] = fixed_bid_bulk_str(bid)
+ else:
+ row_values[_StringTable.BidAdjustment] = bid_multiplier_bulk_str(bid)
class BulkAdGroupProductPartition(_SingleRecordBulkEntity):
""" Represents an Ad Group Criterion that can be read or written in a bulk file.
@@ -38,56 +98,7 @@ def __init__(self,
self._ad_group_name = ad_group_name
self._performance_data = None
- @classmethod
- def _read_is_excluded(cls, entity, row_value):
- if row_value is None:
- row_value = ''
- row_value = row_value.lower()
- if row_value == 'yes' or row_value == 'true':
- is_excluded = True
- elif row_value == 'no' or row_value == 'false':
- is_excluded = False
- else:
- raise ValueError('IsExcluded can only be set to TRUE|FALSE in Ad Group Product Partition row')
- if is_excluded:
- product_partition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductPartition')
- product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductCondition')
- product_partition.Type = 'ProductPartition'
-
- negative_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V12.create('NegativeAdGroupCriterion')
- negative_ad_group_criterion.Criterion = product_partition
- negative_ad_group_criterion.Type = 'NegativeAdGroupCriterion'
-
- entity.ad_group_criterion = negative_ad_group_criterion
- else:
- product_partition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductPartition')
- product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V12.create('ProductCondition')
- product_partition.Type = 'ProductPartition'
-
- fixed_bid = _CAMPAIGN_OBJECT_FACTORY_V12.create('FixedBid')
- fixed_bid.Type = 'FixedBid'
-
- biddable_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V12.create('BiddableAdGroupCriterion')
- biddable_ad_group_criterion.Criterion = product_partition
- biddable_ad_group_criterion.CriterionBid = fixed_bid
- biddable_ad_group_criterion.Type = 'BiddableAdGroupCriterion'
-
- entity.ad_group_criterion = biddable_ad_group_criterion
-
- @classmethod
- def _write_bid(cls, entity):
- criterion = entity.ad_group_criterion
- if isinstance(criterion, _BiddableAdGroupCriterion) and \
- criterion.CriterionBid is not None:
- return fixed_bid_bulk_str(entity.ad_group_criterion.CriterionBid)
-
- @classmethod
- def _read_bid(cls, entity, row_value):
- if isinstance(entity.ad_group_criterion, _BiddableAdGroupCriterion):
- entity.ad_group_criterion.CriterionBid = parse_fixed_bid(row_value)
- else:
- pass
-
+
@classmethod
def _write_destination_url(cls, entity):
if isinstance(entity.ad_group_criterion, _BiddableAdGroupCriterion):
@@ -135,11 +146,9 @@ def _read_destination_url(cls, entity, row_value):
pass
_MAPPINGS = [
- _SimpleBulkMapping(
- _StringTable.IsExcluded,
- field_to_csv=lambda c: 'True' if isinstance(c.ad_group_criterion, _NegativeAdGroupCriterion) else 'False',
- csv_to_field=lambda c, v: BulkAdGroupProductPartition._read_is_excluded(c, v)
- ),
+
+ _ComplexBulkMapping(bidding_to_csv, csv_to_bidding),
+
_SimpleBulkMapping(
_StringTable.Status,
field_to_csv=lambda c: c.ad_group_criterion.Status,
@@ -186,11 +195,7 @@ def _read_destination_url(cls, entity, row_value):
field_to_csv=lambda c: BulkAdGroupProductPartition._get_condition_attribute(c),
csv_to_field=lambda c, v: setattr(c.ad_group_criterion.Criterion.Condition, 'Attribute', v)
),
- _SimpleBulkMapping(
- _StringTable.Bid,
- field_to_csv=lambda c: BulkAdGroupProductPartition._write_bid(c),
- csv_to_field=lambda c, v: BulkAdGroupProductPartition._read_bid(c, v)
- ),
+
_SimpleBulkMapping(
_StringTable.DestinationUrl,
field_to_csv=lambda c: BulkAdGroupProductPartition._write_destination_url(c),
diff --git a/bingads/v12/internal/extensions.py b/bingads/v12/internal/extensions.py
index 4e3e1f91..4bd8bb1d 100644
--- a/bingads/v12/internal/extensions.py
+++ b/bingads/v12/internal/extensions.py
@@ -562,6 +562,11 @@ def fixed_bid_bulk_str(value):
return None
return bulk_str(value.Amount)
+def bid_multiplier_bulk_str(value):
+ if value is None or not hasattr(value, 'Multiplier') or value.Multiplier is None:
+ return None
+ return bulk_str(value.Multiplier)
+
def parse_minute(value):
minute_number = int(value)
if minute_number == 0:
diff --git a/bingads/v13/bulk/entities/bulk_ad_group_product_partition.py b/bingads/v13/bulk/entities/bulk_ad_group_product_partition.py
index 3acd00da..80490aa9 100644
--- a/bingads/v13/bulk/entities/bulk_ad_group_product_partition.py
+++ b/bingads/v13/bulk/entities/bulk_ad_group_product_partition.py
@@ -1,14 +1,74 @@
from bingads.v13.bulk.entities import *
from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V13
from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
-from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
+from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping, _ComplexBulkMapping
from bingads.v13.internal.bulk.string_table import _StringTable
# from bingads.v13.internal.extensions import bulk_str
from bingads.v13.internal.extensions import *
_BiddableAdGroupCriterion = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('BiddableAdGroupCriterion'))
_NegativeAdGroupCriterion = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('NegativeAdGroupCriterion'))
-
+_FixedBid = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('FixedBid'))
+
+def csv_to_bidding(row_values, entity):
+ success, exclude = row_values.try_get_value(_StringTable.IsExcluded)
+ if exclude is None:
+ exclude = ''
+ exclude = exclude.lower()
+ if exclude == 'yes' or exclude == 'true':
+ is_excluded = True
+ elif exclude == 'no' or exclude == 'false':
+ is_excluded = False
+ else:
+ raise ValueError('IsExcluded can only be set to TRUE|FALSE in Ad Group Product Partition row')
+ if is_excluded:
+ product_partition = _CAMPAIGN_OBJECT_FACTORY_V13.create('ProductPartition')
+ product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V13.create('ProductCondition')
+ product_partition.Type = 'ProductPartition'
+
+ negative_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('NegativeAdGroupCriterion')
+ negative_ad_group_criterion.Criterion = product_partition
+ negative_ad_group_criterion.Type = 'NegativeAdGroupCriterion'
+
+ entity.ad_group_criterion = negative_ad_group_criterion
+ else:
+ product_partition = _CAMPAIGN_OBJECT_FACTORY_V13.create('ProductPartition')
+ product_partition.Condition = _CAMPAIGN_OBJECT_FACTORY_V13.create('ProductCondition')
+ product_partition.Type = 'ProductPartition'
+
+ bid = _CAMPAIGN_OBJECT_FACTORY_V13.create('FixedBid')
+ bid.Type = 'FixedBid'
+
+ biddable_ad_group_criterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('BiddableAdGroupCriterion')
+ biddable_ad_group_criterion.Criterion = product_partition
+
+ success, bid_value = row_values.try_get_value(_StringTable.Bid)
+ if success and bid_value is not None and bid_value != '':
+ bid.Amount = float(bid_value)
+ else:
+ success, bid_value = row_values.try_get_value(_StringTable.BidAdjustment)
+ if success and bid_value is not None and bid_value != '':
+ bid = _CAMPAIGN_OBJECT_FACTORY_V13.create('BidMultiplier')
+ bid.Type = 'BidMultiplier'
+ bid.Multiplier = float(bid_value)
+
+ biddable_ad_group_criterion.CriterionBid = bid
+ biddable_ad_group_criterion.Type = 'BiddableAdGroupCriterion'
+
+ entity.ad_group_criterion = biddable_ad_group_criterion
+
+def bidding_to_csv(entity, row_values):
+ if isinstance(entity.ad_group_criterion, _NegativeAdGroupCriterion):
+ row_values[_StringTable.IsExcluded] = 'True'
+ else:
+ row_values[_StringTable.IsExcluded] = 'False'
+ bid = entity.ad_group_criterion.CriterionBid
+ if bid is None:
+ return
+ if isinstance(bid, _FixedBid):
+ row_values[_StringTable.Bid] = fixed_bid_bulk_str(bid)
+ else:
+ row_values[_StringTable.BidAdjustment] = bid_multiplier_bulk_str(bid)
class BulkAdGroupProductPartition(_SingleRecordBulkEntity):
""" Represents an Ad Group Criterion that can be read or written in a bulk file.
@@ -134,11 +194,8 @@ def _read_destination_url(cls, entity, row_value):
pass
_MAPPINGS = [
- _SimpleBulkMapping(
- _StringTable.IsExcluded,
- field_to_csv=lambda c: 'True' if isinstance(c.ad_group_criterion, _NegativeAdGroupCriterion) else 'False',
- csv_to_field=lambda c, v: BulkAdGroupProductPartition._read_is_excluded(c, v)
- ),
+ _ComplexBulkMapping(bidding_to_csv, csv_to_bidding),
+
_SimpleBulkMapping(
_StringTable.Status,
field_to_csv=lambda c: c.ad_group_criterion.Status,
@@ -185,11 +242,6 @@ def _read_destination_url(cls, entity, row_value):
field_to_csv=lambda c: BulkAdGroupProductPartition._get_condition_attribute(c),
csv_to_field=lambda c, v: setattr(c.ad_group_criterion.Criterion.Condition, 'Attribute', v)
),
- _SimpleBulkMapping(
- _StringTable.Bid,
- field_to_csv=lambda c: BulkAdGroupProductPartition._write_bid(c),
- csv_to_field=lambda c, v: BulkAdGroupProductPartition._read_bid(c, v)
- ),
_SimpleBulkMapping(
_StringTable.DestinationUrl,
field_to_csv=lambda c: BulkAdGroupProductPartition._write_destination_url(c),
diff --git a/bingads/v13/internal/extensions.py b/bingads/v13/internal/extensions.py
index 22f3511c..27b634d6 100644
--- a/bingads/v13/internal/extensions.py
+++ b/bingads/v13/internal/extensions.py
@@ -562,6 +562,11 @@ def fixed_bid_bulk_str(value):
return None
return bulk_str(value.Amount)
+def bid_multiplier_bulk_str(value):
+ if value is None or not hasattr(value, 'Multiplier') or value.Multiplier is None:
+ return None
+ return bulk_str(value.Multiplier)
+
def parse_minute(value):
minute_number = int(value)
if minute_number == 0:
diff --git a/bingads/v13/proxies/campaign_management_service.xml b/bingads/v13/proxies/campaign_management_service.xml
index 96151e27..6926fee7 100644
--- a/bingads/v13/proxies/campaign_management_service.xml
+++ b/bingads/v13/proxies/campaign_management_service.xml
@@ -1707,11 +1707,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2017,6 +2031,7 @@
+
@@ -2039,6 +2054,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -2184,6 +2210,7 @@
+
diff --git a/setup.py b/setup.py
index d5813dd6..a7252ff3 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
except ImportError:
from distutils.core import setup
-VERSION = '12.13.4.1'
+VERSION = '12.13.5'
with open('README.rst', 'r') as f:
readme = f.read()