This commit is contained in:
2026-05-16 21:55:40 +02:00
parent 173d734d04
commit 045763576b
10 changed files with 116 additions and 220 deletions

1
.obsidian/app.json vendored
View File

@@ -1 +0,0 @@
{}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1,33 +0,0 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

View File

@@ -1,181 +0,0 @@
{
"main": {
"id": "3f59f5e90e59eb16",
"type": "split",
"children": [
{
"id": "2dc50d9d622925dd",
"type": "tabs",
"children": [
{
"id": "50874c953e5f9bdd",
"type": "leaf",
"state": {
"type": "empty",
"state": {},
"icon": "lucide-file",
"title": "Nowa karta"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "4ea9df900d7f5928",
"type": "split",
"children": [
{
"id": "2612d8ccef263088",
"type": "tabs",
"children": [
{
"id": "8da90c1bd15733b5",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Przeglądarka plików"
}
},
{
"id": "32d60256220fa10d",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Wyszukiwarka"
}
},
{
"id": "ba8eb9c149202945",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Ulubione"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "eba8ccc69c4fa26a",
"type": "split",
"children": [
{
"id": "23e5acb3c0462964",
"type": "tabs",
"children": [
{
"id": "a0c3faa7e6698dca",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Linki zwrotne"
}
},
{
"id": "a15cf2efefb71448",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Łącza wychodzące"
}
},
{
"id": "b85e3764a86214ff",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tagi"
}
},
{
"id": "add518694a71d3d5",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "Wszystkie atrybuty"
}
},
{
"id": "159050c414a15880",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Konspekt"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Otwórz okno szybkiego wyboru": false,
"graph:Otwórz podgląd grafu": false,
"canvas:Stwórz nową tablicę": false,
"daily-notes:Otwórz dzisiejszy dziennik": false,
"templates:Wstaw szablon": false,
"command-palette:Otwórz listę poleceń": false,
"bases:Stwórz nową bazę danych": false
}
},
"active": "50874c953e5f9bdd",
"lastOpenFiles": []
}

View File

@@ -197,6 +197,20 @@ W kodzie uzywaj:
rules = client_config.effective_rules(global_rules, "search_settings") rules = client_config.effective_rules(global_rules, "search_settings")
``` ```
## Pominiecia zadan przy ALL
Jesli zadanie ma byc pomijane tylko przy pelnym wyborze `ALL` / `--all-groups`,
dodaj je przy konkretnym kliencie:
```toml
[clients."example.pl"]
google_ads_customer_id = "123-456-7890"
skip_in_all = ["split_pla_cl1_bestsellers"]
```
Pominiecie dotyczy tylko `ALL` / `--all-groups`. Reczny wybor zadania albo grupy
nadal uruchamia wskazany zakres.
## Numeracja i wybory ## Numeracja i wybory
Lista zadan uzywa formatu: Lista zadan uzywa formatu:

View File

@@ -105,6 +105,7 @@ Pierwsze zadanie:
- `config/clients.toml` - lista klientow i identyfikatory kont. - `config/clients.toml` - lista klientow i identyfikatory kont.
- `config/clients.toml` - takze reguly globalne i wyjatki per klient, np. ustawienia kampanii PLA. - `config/clients.toml` - takze reguly globalne i wyjatki per klient, np. ustawienia kampanii PLA.
- `config/clients.toml` - takze pominiecia zadan przy wyborze `ALL`, np. `skip_in_all` w sekcji klienta.
- `.env` - dane dostepowe do Google Ads i adsPRO. - `.env` - dane dostepowe do Google Ads i adsPRO.
- `clients/<domena>/data/` - pobrane dane robocze. - `clients/<domena>/data/` - pobrane dane robocze.
- `clients/<domena>/history/YYYY-MM-DD.jsonl` - historia do filtrowania po kliencie, dacie i kampanii. - `clients/<domena>/history/YYYY-MM-DD.jsonl` - historia do filtrowania po kliencie, dacie i kampanii.

View File

@@ -1,6 +1,7 @@
[clients."example.pl"] [clients."example.pl"]
google_ads_customer_id = "123-456-7890" google_ads_customer_id = "123-456-7890"
adspro_client_id = "1" adspro_client_id = "1"
skip_in_all = []
[global_rules] [global_rules]
max_create_groups_without_extra_confirm = 100 max_create_groups_without_extra_confirm = 100

View File

@@ -5,13 +5,16 @@ adspro_client_id = "2"
[clients."innsi.pl"] [clients."innsi.pl"]
google_ads_customer_id = "133-343-6346" google_ads_customer_id = "133-343-6346"
adspro_client_id = "5" adspro_client_id = "5"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."van-dam.pl"] [clients."van-dam.pl"]
google_ads_customer_id = "570-658-4790" google_ads_customer_id = "570-658-4790"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."investagd.pl"] [clients."investagd.pl"]
google_ads_customer_id = "229-855-5588" google_ads_customer_id = "229-855-5588"
adspro_client_id = "8" adspro_client_id = "8"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."investagd.pl".product_availability] [clients."investagd.pl".product_availability]
method = "html_buy_button" method = "html_buy_button"
@@ -23,10 +26,12 @@ target_unavailable_label = "paused"
[clients."wyprzedaze.pl"] [clients."wyprzedaze.pl"]
google_ads_customer_id = "775-249-3197" google_ads_customer_id = "775-249-3197"
adspro_client_id = "10" adspro_client_id = "10"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."laitica.pl"] [clients."laitica.pl"]
google_ads_customer_id = "262-567-7205" google_ads_customer_id = "262-567-7205"
adspro_client_id = "9" adspro_client_id = "9"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."laitica.pl".product_availability] [clients."laitica.pl".product_availability]
method = "shopify_products_json" method = "shopify_products_json"
@@ -35,6 +40,7 @@ target_unavailable_label = "paused"
[clients."studio-zoe.pl"] [clients."studio-zoe.pl"]
google_ads_customer_id = "387-166-1050" google_ads_customer_id = "387-166-1050"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."aruba.rzeszow.pl"] [clients."aruba.rzeszow.pl"]
google_ads_customer_id = "374-470-8609" google_ads_customer_id = "374-470-8609"
@@ -42,11 +48,13 @@ adspro_client_id = "3"
sales_history_sheet = "https://docs.google.com/spreadsheets/d/1tkT1WgOi41uj7D0Q8ZTD0qINsd11VVsd7G9Q7M8kAN8/" sales_history_sheet = "https://docs.google.com/spreadsheets/d/1tkT1WgOi41uj7D0Q8ZTD0qINsd11VVsd7G9Q7M8kAN8/"
seo_works_history_sheet = "https://docs.google.com/spreadsheets/d/1lle7nkl0ykkJMlo2eA8AuV7Sd705ia6bmh7RM38nsRg/" seo_works_history_sheet = "https://docs.google.com/spreadsheets/d/1lle7nkl0ykkJMlo2eA8AuV7Sd705ia6bmh7RM38nsRg/"
seo_links_history_sheet = "https://docs.google.com/spreadsheets/d/1b4uCBzNSFFxIv2X1fTsqZcdDr7NZZYOIsmc9kLJqkq0/" seo_links_history_sheet = "https://docs.google.com/spreadsheets/d/1b4uCBzNSFFxIv2X1fTsqZcdDr7NZZYOIsmc9kLJqkq0/"
skip_in_all = ["split_pla_cl1_bestsellers"]
[clients."ibra-makeup.pl"] [clients."ibra-makeup.pl"]
google_ads_customer_id = "818-919-2566" google_ads_customer_id = "818-919-2566"
adspro_client_id = "4" adspro_client_id = "4"
sales_history_sheet = "https://docs.google.com/spreadsheets/d/1OGqRluQgd2vCVxbmVLhPd00q8RWucSc0L4GdcGAl8vU" sales_history_sheet = "https://docs.google.com/spreadsheets/d/1OGqRluQgd2vCVxbmVLhPd00q8RWucSc0L4GdcGAl8vU"
skip_in_all = ["split_pla_cl1_bestsellers"]
[global_rules] [global_rules]
max_create_groups_without_extra_confirm = 100 max_create_groups_without_extra_confirm = 100

View File

@@ -113,6 +113,47 @@ def choose_index(label: str, options: list[str]) -> int | None:
return idx - 1 return idx - 1
def _task_id_set(value) -> set[str]:
if value is None:
return set()
if isinstance(value, str):
values = [value]
elif isinstance(value, (list, tuple, set)):
values = value
else:
return set()
return {str(item).strip() for item in values if str(item).strip()}
def all_selection_skip_task_ids(client) -> set[str]:
return _task_id_set(client.skip_in_all)
def tasks_for_all_selection(tasks, client):
skipped_ids = all_selection_skip_task_ids(client)
if not skipped_ids:
return list(tasks), []
selected = []
skipped = []
for task in tasks:
if task.id in skipped_ids:
skipped.append(task)
else:
selected.append(task)
return selected, skipped
def print_all_selection_skips(client, skipped_tasks) -> None:
if not skipped_tasks:
return
print()
print("Pominieto w wyborze ALL zgodnie z config/clients.toml:")
print_table(
["Nr", "Task ID", "Zadanie"],
[[task.selection, task.id, task.name] for task in skipped_tasks],
)
def main() -> None: def main() -> None:
if hasattr(sys.stdout, "reconfigure"): if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace") sys.stdout.reconfigure(encoding="utf-8", errors="replace")
@@ -307,9 +348,17 @@ def main() -> None:
if args.select: if args.select:
selected = args.select.strip() selected = args.select.strip()
if selected.upper() == "ALL": if selected.upper() == "ALL":
run_task_sequence( selected_tasks, skipped_tasks = tasks_for_all_selection(
tasks, tasks,
cfg.clients[selected_domain], cfg.clients[selected_domain],
)
print_all_selection_skips(cfg.clients[selected_domain], skipped_tasks)
if not selected_tasks:
print("Brak zadan do uruchomienia po zastosowaniu pominiec dla ALL.")
return
run_task_sequence(
selected_tasks,
cfg.clients[selected_domain],
cfg.global_rules, cfg.global_rules,
plan_only=args.plan_only, plan_only=args.plan_only,
) )
@@ -365,9 +414,17 @@ def main() -> None:
return return
if args.all_groups: if args.all_groups:
run_task_sequence( selected_tasks, skipped_tasks = tasks_for_all_selection(
tasks, tasks,
cfg.clients[selected_domain], cfg.clients[selected_domain],
)
print_all_selection_skips(cfg.clients[selected_domain], skipped_tasks)
if not selected_tasks:
print("Brak zadan do uruchomienia po zastosowaniu pominiec dla ALL.")
return
run_task_sequence(
selected_tasks,
cfg.clients[selected_domain],
cfg.global_rules, cfg.global_rules,
plan_only=args.plan_only, plan_only=args.plan_only,
) )
@@ -419,10 +476,12 @@ def main() -> None:
return return
selected_tasks = [] selected_tasks = []
respect_all_skips = False
if args.select: if args.select:
selected = args.select.strip() selected = args.select.strip()
if selected.upper() == "ALL": if selected.upper() == "ALL":
selected_tasks = tasks selected_tasks = tasks
respect_all_skips = True
else: else:
selected_tasks = tasks_by_selection_group(tasks, groups, selected) selected_tasks = tasks_by_selection_group(tasks, groups, selected)
if not selected_tasks: if not selected_tasks:
@@ -438,6 +497,7 @@ def main() -> None:
return return
elif args.all_groups: elif args.all_groups:
selected_tasks = tasks selected_tasks = tasks
respect_all_skips = True
elif args.task: elif args.task:
selected_tasks = [task for task in tasks if task.id == args.task] selected_tasks = [task for task in tasks if task.id == args.task]
if not selected_tasks: if not selected_tasks:
@@ -456,6 +516,7 @@ def main() -> None:
domains, domains,
plan_only=True, plan_only=True,
pause_after_client=True, pause_after_client=True,
respect_all_skips=respect_all_skips,
) )
return return
@@ -1762,6 +1823,7 @@ def run_tasks_for_all_clients(
domains: list[str], domains: list[str],
plan_only: bool = True, plan_only: bool = True,
pause_after_client: bool = True, pause_after_client: bool = True,
respect_all_skips: bool = False,
) -> None: ) -> None:
total_clients = len(domains) total_clients = len(domains)
total_tasks = len(tasks) total_tasks = len(tasks)
@@ -1782,10 +1844,22 @@ def run_tasks_for_all_clients(
print("#" * 72) print("#" * 72)
print(f"Klient {client_index}/{total_clients}: {domain}") print(f"Klient {client_index}/{total_clients}: {domain}")
print("#" * 72) print("#" * 72)
for task_index, task in enumerate(tasks, 1): client_tasks = list(tasks)
skipped_tasks = []
if respect_all_skips:
client_tasks, skipped_tasks = tasks_for_all_selection(
tasks,
cfg.clients[domain],
)
print_all_selection_skips(cfg.clients[domain], skipped_tasks)
total_client_tasks = len(client_tasks)
if not client_tasks:
print("Brak zadan do uruchomienia po zastosowaniu pominiec dla ALL.")
continue
for task_index, task in enumerate(client_tasks, 1):
print() print()
print("-" * 72) print("-" * 72)
print(f"Zadanie {task_index}/{total_tasks}: {task.group_name} / {task.name}") print(f"Zadanie {task_index}/{total_client_tasks}: {task.group_name} / {task.name}")
print("-" * 72) print("-" * 72)
try: try:
run_task( run_task(

View File

@@ -27,6 +27,7 @@ class ClientConfig:
domain: str domain: str
google_ads_customer_id: str google_ads_customer_id: str
adspro_client_id: str | None = None adspro_client_id: str | None = None
skip_in_all: tuple[str, ...] = ()
rules: dict | None = None rules: dict | None = None
@property @property
@@ -45,6 +46,18 @@ class AppConfig:
global_rules: dict global_rules: dict
def _string_tuple(value) -> tuple[str, ...]:
if value is None:
return ()
if isinstance(value, str):
values = [value]
elif isinstance(value, (list, tuple, set)):
values = value
else:
return ()
return tuple(str(item).strip() for item in values if str(item).strip())
def load_config(path: Path | None = None) -> AppConfig: def load_config(path: Path | None = None) -> AppConfig:
config_path = path or ROOT / "config" / "clients.toml" config_path = path or ROOT / "config" / "clients.toml"
if not config_path.exists(): if not config_path.exists():
@@ -59,6 +72,7 @@ def load_config(path: Path | None = None) -> AppConfig:
domain=domain, domain=domain,
google_ads_customer_id=str(row["google_ads_customer_id"]), google_ads_customer_id=str(row["google_ads_customer_id"]),
adspro_client_id=str(row.get("adspro_client_id")) if row.get("adspro_client_id") else None, adspro_client_id=str(row.get("adspro_client_id")) if row.get("adspro_client_id") else None,
skip_in_all=_string_tuple(row.get("skip_in_all")),
rules={key: value for key, value in row.items() if isinstance(value, dict)}, rules={key: value for key, value in row.items() if isinstance(value, dict)},
) )
return AppConfig(clients=clients, global_rules=data.get("global_rules", {})) return AppConfig(clients=clients, global_rules=data.get("global_rules", {}))