diff --git a/README.md b/README.md index af411eb3..1515fc7e 100644 --- a/README.md +++ b/README.md @@ -495,6 +495,7 @@ direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 30000 direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run +direct bidmodifiers add --campaign-id 123 --type MOBILE_ADJUSTMENT --value 120 --operating-system-type IOS --dry-run direct bidmodifiers set --id 99 --value 130 --dry-run # Canonical multiword groups @@ -1202,6 +1203,7 @@ direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 30000 direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run +direct bidmodifiers add --campaign-id 123 --type MOBILE_ADJUSTMENT --value 120 --operating-system-type IOS --dry-run direct bidmodifiers set --id 99 --value 130 --dry-run # Канонические многословные группы diff --git a/direct_cli/commands/bidmodifiers.py b/direct_cli/commands/bidmodifiers.py index 1cc9f2e7..9711f064 100644 --- a/direct_cli/commands/bidmodifiers.py +++ b/direct_cli/commands/bidmodifiers.py @@ -125,9 +125,11 @@ def get( v for v in _BIDMODIFIER_TYPE_TO_NESTED.values() if v.endswith("Adjustments") } +_OPERATING_SYSTEM_TYPE_MODIFIERS = {"MOBILE_ADJUSTMENT", "TABLET_ADJUSTMENT"} + _BIDMODIFIER_ALLOWED_EXTRA_FLAGS = { - "MOBILE_ADJUSTMENT": set(), - "TABLET_ADJUSTMENT": set(), + "MOBILE_ADJUSTMENT": {"--operating-system-type"}, + "TABLET_ADJUSTMENT": {"--operating-system-type"}, "DESKTOP_ADJUSTMENT": set(), "DESKTOP_ONLY_ADJUSTMENT": set(), "SMART_TV_ADJUSTMENT": set(), @@ -190,6 +192,14 @@ def _reject_incompatible_extra_flags( @click.option("--region-id", type=int, help="Regional adjustment region ID") @click.option("--serp-layout", help="SERP layout adjustment value") @click.option("--income-grade", help="Income grade adjustment value") +@click.option( + "--operating-system-type", + type=click.Choice(["IOS", "ANDROID"], case_sensitive=False), + help=( + "Operating system type for MobileAdjustment.OperatingSystemType or " + "TabletAdjustment.OperatingSystemType." + ), +) @click.option("--dry-run", is_flag=True, help="Show request without sending") @click.pass_context def add( @@ -204,6 +214,7 @@ def add( region_id, serp_layout, income_grade, + operating_system_type, dry_run, ): """Add a new bid modifier @@ -235,11 +246,17 @@ def add( "--region-id": region_id, "--serp-layout": serp_layout, "--income-grade": income_grade, + "--operating-system-type": operating_system_type, }, ) nested_key = _BIDMODIFIER_TYPE_TO_NESTED[modifier_type_upper] nested = {"BidModifier": value} + if ( + modifier_type_upper in _OPERATING_SYSTEM_TYPE_MODIFIERS + and operating_system_type + ): + nested["OperatingSystemType"] = operating_system_type.upper() if modifier_type_upper == "DEMOGRAPHICS_ADJUSTMENT": if gender: nested["Gender"] = gender diff --git a/tests/WSDL_OPTIONAL_FIELD_AUDIT.md b/tests/WSDL_OPTIONAL_FIELD_AUDIT.md index f61803df..7f14540e 100644 --- a/tests/WSDL_OPTIONAL_FIELD_AUDIT.md +++ b/tests/WSDL_OPTIONAL_FIELD_AUDIT.md @@ -11,8 +11,8 @@ be classified as `supported`, `missing_followup`, or `not_applicable`. | Status | Count | |---|---:| -| `missing_followup` | 2817 | -| `supported` | 424 | +| `missing_followup` | 2815 | +| `supported` | 426 | ## Confirmed Follow-Ups @@ -353,8 +353,6 @@ be classified as `supported`, `missing_followup`, or `not_applicable`. | `ads.update` | `ListingAd.DefaultTexts` | LISTING_AD update fields need typed support or N/A. [#269](https://github.com/axisrow/direct-cli/issues/269); inherited from `ListingAd` | | `audiencetargets.add` | `ContextBid` | target bid optional WSDL path needs typed support or N/A. [#302](https://github.com/axisrow/direct-cli/issues/302) | | `audiencetargets.add` | `StrategyPriority` | target bid optional WSDL path needs typed support or N/A. [#302](https://github.com/axisrow/direct-cli/issues/302) | -| `bidmodifiers.add` | `MobileAdjustment.OperatingSystemType` | bidmodifiers.add optional WSDL path needs typed support or N/A. [#254](https://github.com/axisrow/direct-cli/issues/254) | -| `bidmodifiers.add` | `TabletAdjustment.OperatingSystemType` | bidmodifiers.add optional WSDL path needs typed support or N/A. [#254](https://github.com/axisrow/direct-cli/issues/254) | | `bids.set` | `CampaignId` | bids.set optional WSDL path needs typed support or N/A. [#301](https://github.com/axisrow/direct-cli/issues/301) | | `bids.set` | `AdGroupId` | bids.set optional WSDL path needs typed support or N/A. [#301](https://github.com/axisrow/direct-cli/issues/301) | | `bids.set` | `ContextBid` | bids.set optional WSDL path needs typed support or N/A. [#301](https://github.com/axisrow/direct-cli/issues/301) | @@ -3266,14 +3264,14 @@ be classified as `supported`, `missing_followup`, or `not_applicable`. | `bidmodifiers.add` | `bidmodifiers.add` | `AdGroupId` | `long` | 0 | 1 | `supported` | --adgroup-id | | `bidmodifiers.add` | `bidmodifiers.add` | `MobileAdjustment` | `MobileAdjustmentAdd` | 0 | 1 | `supported` | --type | | `bidmodifiers.add` | `bidmodifiers.add` | `MobileAdjustment.BidModifier` | `int` | 1 | 1 | `supported` | --value | -| `bidmodifiers.add` | `bidmodifiers.add` | `MobileAdjustment.OperatingSystemType` | `OperatingSystemTypeEnum` | 0 | 1 | `missing_followup` | bidmodifiers.add optional WSDL path needs typed support or N/A. [#254](https://github.com/axisrow/direct-cli/issues/254) | +| `bidmodifiers.add` | `bidmodifiers.add` | `MobileAdjustment.OperatingSystemType` | `OperatingSystemTypeEnum` | 0 | 1 | `supported` | --operating-system-type | | `bidmodifiers.add` | `bidmodifiers.add` | `DesktopAdjustment` | `DesktopAdjustmentAdd` | 0 | 1 | `supported` | --type | | `bidmodifiers.add` | `bidmodifiers.add` | `DesktopAdjustment.BidModifier` | `int` | 1 | 1 | `supported` | --value | | `bidmodifiers.add` | `bidmodifiers.add` | `SmartTvAdjustment` | `SmartTvAdjustmentAdd` | 0 | 1 | `supported` | --type | | `bidmodifiers.add` | `bidmodifiers.add` | `SmartTvAdjustment.BidModifier` | `int` | 1 | 1 | `supported` | --value | | `bidmodifiers.add` | `bidmodifiers.add` | `TabletAdjustment` | `TabletAdjustmentAdd` | 0 | 1 | `supported` | --type | | `bidmodifiers.add` | `bidmodifiers.add` | `TabletAdjustment.BidModifier` | `int` | 1 | 1 | `supported` | --value | -| `bidmodifiers.add` | `bidmodifiers.add` | `TabletAdjustment.OperatingSystemType` | `OperatingSystemTypeEnum` | 0 | 1 | `missing_followup` | bidmodifiers.add optional WSDL path needs typed support or N/A. [#254](https://github.com/axisrow/direct-cli/issues/254) | +| `bidmodifiers.add` | `bidmodifiers.add` | `TabletAdjustment.OperatingSystemType` | `OperatingSystemTypeEnum` | 0 | 1 | `supported` | --operating-system-type | | `bidmodifiers.add` | `bidmodifiers.add` | `DesktopOnlyAdjustment` | `DesktopOnlyAdjustmentAdd` | 0 | 1 | `supported` | --type | | `bidmodifiers.add` | `bidmodifiers.add` | `DesktopOnlyAdjustment.BidModifier` | `int` | 1 | 1 | `supported` | --value | | `bidmodifiers.add` | `bidmodifiers.add` | `DemographicsAdjustments` | `DemographicsAdjustmentAdd` | 0 | unbounded | `supported` | --type | diff --git a/tests/test_dry_run.py b/tests/test_dry_run.py index e011fa52..7e0856c2 100644 --- a/tests/test_dry_run.py +++ b/tests/test_dry_run.py @@ -3307,6 +3307,48 @@ def test_bidmodifiers_add_mobile_uses_nested_object(): assert modifier["MobileAdjustment"] == {"BidModifier": 120} +def test_bidmodifiers_add_mobile_operating_system_type(): + body = _dry_run( + "bidmodifiers", + "add", + "--campaign-id", + "1", + "--type", + "MOBILE_ADJUSTMENT", + "--value", + "120", + "--operating-system-type", + "ios", + ) + + modifier = body["params"]["BidModifiers"][0] + assert modifier["MobileAdjustment"] == { + "BidModifier": 120, + "OperatingSystemType": "IOS", + } + + +def test_bidmodifiers_add_tablet_operating_system_type(): + body = _dry_run( + "bidmodifiers", + "add", + "--campaign-id", + "1", + "--type", + "TABLET_ADJUSTMENT", + "--value", + "120", + "--operating-system-type", + "ANDROID", + ) + + modifier = body["params"]["BidModifiers"][0] + assert modifier["TabletAdjustment"] == { + "BidModifier": 120, + "OperatingSystemType": "ANDROID", + } + + def test_bidmodifiers_add_rejects_incompatible_extra_flags(): mobile_result = _rejected( "bidmodifiers", @@ -3332,6 +3374,18 @@ def test_bidmodifiers_add_rejects_incompatible_extra_flags(): "--retargeting-condition-id", "123", ) + desktop_result = _rejected( + "bidmodifiers", + "add", + "--campaign-id", + "1", + "--type", + "DESKTOP_ADJUSTMENT", + "--value", + "120", + "--operating-system-type", + "IOS", + ) assert ( "--gender is not compatible with --type MOBILE_ADJUSTMENT" @@ -3341,6 +3395,9 @@ def test_bidmodifiers_add_rejects_incompatible_extra_flags(): "--retargeting-condition-id is not compatible with --type " "DEMOGRAPHICS_ADJUSTMENT" ) in demographics_result.output + assert ( + "--operating-system-type is not compatible with --type DESKTOP_ADJUSTMENT" + ) in desktop_result.output def test_bidmodifiers_add_income_grade_uses_wsdl_grade_field(): diff --git a/tests/test_wsdl_parity_gate.py b/tests/test_wsdl_parity_gate.py index 64b6dafa..87f213d5 100644 --- a/tests/test_wsdl_parity_gate.py +++ b/tests/test_wsdl_parity_gate.py @@ -949,6 +949,12 @@ def test_silent_data_loss_rejected( ("bidmodifiers", "add", "RegionalAdjustments.RegionId"): {"--region-id"}, ("bidmodifiers", "add", "SerpLayoutAdjustments.SerpLayout"): {"--serp-layout"}, ("bidmodifiers", "add", "IncomeGradeAdjustments.Grade"): {"--income-grade"}, + ("bidmodifiers", "add", "MobileAdjustment.OperatingSystemType"): { + "--operating-system-type" + }, + ("bidmodifiers", "add", "TabletAdjustment.OperatingSystemType"): { + "--operating-system-type" + }, } )