update
This commit is contained in:
@@ -116,6 +116,15 @@ def normalize_text(value: str) -> str:
|
||||
)
|
||||
|
||||
|
||||
def ad_group_name_for_product(product: dict, duplicate_title: bool = False) -> str:
|
||||
title = (product.get("title") or "").strip()
|
||||
offer_id = (product.get("offer_id") or "").strip()
|
||||
if not duplicate_title or not offer_id:
|
||||
return title
|
||||
suffix = f" | {offer_id}"
|
||||
return f"{title[:255 - len(suffix)]}{suffix}"
|
||||
|
||||
|
||||
def parse_allowed_labels(campaign_name: str) -> set[str]:
|
||||
match = re.search(r"\]\s*(.+)$", campaign_name)
|
||||
raw = match.group(1).strip() if match else campaign_name
|
||||
@@ -128,6 +137,10 @@ def normalize_variant(value: str) -> str:
|
||||
return (value or "").strip().lower()
|
||||
|
||||
|
||||
def product_has_paused_cl4(product: dict) -> bool:
|
||||
return normalize_variant(product.get("custom_label_4")) == "paused"
|
||||
|
||||
|
||||
def parse_campaign_variant(campaign_name: str) -> str:
|
||||
"""Wariant kampanii z czesci po znaku '|' w nazwie, np. 'catch_all'.
|
||||
|
||||
@@ -335,6 +348,7 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
products_by_campaign = defaultdict(list)
|
||||
fallback_offers = []
|
||||
orphan_offers = []
|
||||
paused_offers = []
|
||||
for product in products:
|
||||
offer_id = (product.get("offer_id") or "").strip()
|
||||
title = (product.get("title") or "").strip()
|
||||
@@ -345,6 +359,9 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
by_title_norm[normalize_text(title)].append(product)
|
||||
if not (label and title and offer_id):
|
||||
continue
|
||||
if product_has_paused_cl4(product):
|
||||
paused_offers.append(offer_id)
|
||||
continue
|
||||
target, used_fallback = resolve_target_campaign(product)
|
||||
if target is None:
|
||||
orphan_offers.append(offer_id)
|
||||
@@ -413,7 +430,16 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
if record["ad_group_status"] == "ENABLED":
|
||||
enabled_offers_by_campaign[record["campaign_id"]].add(record["offer_id"])
|
||||
|
||||
title_counts_by_campaign = defaultdict(Counter)
|
||||
for campaign_id, campaign_products in products_by_campaign.items():
|
||||
title_counts_by_campaign[campaign_id].update(
|
||||
normalize_text(product.get("title") or "")
|
||||
for product in campaign_products
|
||||
if (product.get("title") or "").strip()
|
||||
)
|
||||
|
||||
wrong_groups = []
|
||||
paused_product_groups = []
|
||||
groups_without_match = []
|
||||
active_groups_without_match = []
|
||||
rename_plan = []
|
||||
@@ -422,7 +448,7 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
match_via = "offer_id" if product else None
|
||||
if not product:
|
||||
candidates = by_title_norm.get(normalize_text(group["ad_group_name"])) or []
|
||||
if candidates:
|
||||
if len(candidates) == 1:
|
||||
product = candidates[0]
|
||||
match_via = "title"
|
||||
if not product:
|
||||
@@ -430,6 +456,10 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
if group["ad_group_status"] == "ENABLED":
|
||||
active_groups_without_match.append(group)
|
||||
continue
|
||||
if product_has_paused_cl4(product):
|
||||
if group["ad_group_status"] == "ENABLED":
|
||||
paused_product_groups.append((group, product))
|
||||
continue
|
||||
label = (product.get("custom_label_1") or "").strip()
|
||||
if not label:
|
||||
if group["ad_group_status"] == "ENABLED":
|
||||
@@ -445,7 +475,11 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
# Zla kampania albo zly wariant (np. CL4 puste, a grupa w kampanii | catch_all).
|
||||
wrong_groups.append((group, product))
|
||||
continue
|
||||
adspro_title = (product.get("title") or "").strip()
|
||||
title_key = normalize_text(product.get("title") or "")
|
||||
duplicate_title = False
|
||||
if target and title_key:
|
||||
duplicate_title = title_counts_by_campaign[target["id"]][title_key] > 1
|
||||
adspro_title = ad_group_name_for_product(product, duplicate_title)
|
||||
if (
|
||||
group["ad_group_status"] == "ENABLED"
|
||||
and match_via == "offer_id"
|
||||
@@ -468,7 +502,9 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
|
||||
def plan_enable_or_create(campaign: dict, product: dict, fallback_name: str, reason: str) -> None:
|
||||
offer_id = (product.get("offer_id") or "").strip()
|
||||
title = (product.get("title") or "").strip() or fallback_name
|
||||
title_key = normalize_text(product.get("title") or "")
|
||||
duplicate_title = title_key and title_counts_by_campaign[campaign["id"]][title_key] > 1
|
||||
title = ad_group_name_for_product(product, bool(duplicate_title)) or fallback_name
|
||||
if not offer_id or not title:
|
||||
return
|
||||
if offer_id in enabled_offers_by_campaign[campaign["id"]]:
|
||||
@@ -477,11 +513,13 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
# Najpierw szukamy grupy reklam po produkcie (offer_id), a dopiero
|
||||
# potem po nazwie. Dzieki temu istniejaca grupa z tym produktem, ale
|
||||
# pod inna nazwa, zostanie wlaczona i przemianowana, a nie zduplikowana.
|
||||
# Przy zduplikowanych tytulach nie dopasowujemy po samej nazwie, bo jedna
|
||||
# grupa reklam moze wtedy blednie pokryc kilka roznych offer_id.
|
||||
matched_via = None
|
||||
existing_candidates = existing_groups_by_campaign_offer.get((campaign["id"], offer_id), [])
|
||||
if existing_candidates:
|
||||
matched_via = "offer_id"
|
||||
else:
|
||||
elif not duplicate_title:
|
||||
existing_candidates = existing_groups_by_campaign_name.get((campaign["id"], normalize_text(title)), [])
|
||||
if existing_candidates:
|
||||
matched_via = "title"
|
||||
@@ -530,6 +568,15 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
|
||||
wrong_variant_count = 0
|
||||
wrong_segment_count = 0
|
||||
for group, product in paused_product_groups:
|
||||
pause_by_id[group["ad_group_id"]] = {
|
||||
"ad_group_id": group["ad_group_id"],
|
||||
"ad_group_name": group["ad_group_name"],
|
||||
"campaign_id": group["campaign_id"],
|
||||
"campaign_name": group["campaign_name"],
|
||||
"reason": "produkt ma CL4=paused w adsPRO",
|
||||
}
|
||||
|
||||
for group, product in wrong_groups:
|
||||
offer_id = (product.get("offer_id") or "").strip()
|
||||
target = target_by_offer.get(offer_id)
|
||||
@@ -616,6 +663,16 @@ def build_plan(client, customer_id: str, products: list[dict]) -> SyncPlan:
|
||||
f"Produkty z CL4, ale bez kampanii-wariantu, przypisane do kampanii bazowej: "
|
||||
f"{len(fallback_offers)}."
|
||||
)
|
||||
if paused_offers:
|
||||
warnings.append(
|
||||
f"Produkty z CL4=paused pominiete przy tworzeniu i wlaczaniu grup reklam: "
|
||||
f"{len(paused_offers)}."
|
||||
)
|
||||
if paused_product_groups:
|
||||
warnings.append(
|
||||
f"Aktywne grupy reklam produktow z CL4=paused do wstrzymania: "
|
||||
f"{len(paused_product_groups)}."
|
||||
)
|
||||
if orphan_offers:
|
||||
warnings.append(
|
||||
f"Produkty bez pasujacej kampanii PLA_CL1 (CL1/CL4): {len(orphan_offers)}."
|
||||
|
||||
Reference in New Issue
Block a user