diff --git a/.obsidian/app.json b/.obsidian/app.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.obsidian/app.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.obsidian/appearance.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json deleted file mode 100644 index 639b90d..0000000 --- a/.obsidian/core-plugins.json +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json deleted file mode 100644 index 46e5b93..0000000 --- a/.obsidian/workspace.json +++ /dev/null @@ -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": [] -} \ No newline at end of file diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 6efcd85..e6081c2 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -197,6 +197,20 @@ W kodzie uzywaj: 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 Lista zadan uzywa formatu: diff --git a/README.md b/README.md index 463afe6..9968707 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Pierwsze zadanie: - `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 pominiecia zadan przy wyborze `ALL`, np. `skip_in_all` w sekcji klienta. - `.env` - dane dostepowe do Google Ads i adsPRO. - `clients//data/` - pobrane dane robocze. - `clients//history/YYYY-MM-DD.jsonl` - historia do filtrowania po kliencie, dacie i kampanii. diff --git a/config/clients.example.toml b/config/clients.example.toml index 29ff261..867640d 100644 --- a/config/clients.example.toml +++ b/config/clients.example.toml @@ -1,6 +1,7 @@ [clients."example.pl"] google_ads_customer_id = "123-456-7890" adspro_client_id = "1" +skip_in_all = [] [global_rules] max_create_groups_without_extra_confirm = 100 diff --git a/config/clients.toml b/config/clients.toml index e08a87e..ebd9f12 100644 --- a/config/clients.toml +++ b/config/clients.toml @@ -5,13 +5,16 @@ adspro_client_id = "2" [clients."innsi.pl"] google_ads_customer_id = "133-343-6346" adspro_client_id = "5" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."van-dam.pl"] google_ads_customer_id = "570-658-4790" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."investagd.pl"] google_ads_customer_id = "229-855-5588" adspro_client_id = "8" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."investagd.pl".product_availability] method = "html_buy_button" @@ -23,10 +26,12 @@ target_unavailable_label = "paused" [clients."wyprzedaze.pl"] google_ads_customer_id = "775-249-3197" adspro_client_id = "10" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."laitica.pl"] google_ads_customer_id = "262-567-7205" adspro_client_id = "9" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."laitica.pl".product_availability] method = "shopify_products_json" @@ -35,6 +40,7 @@ target_unavailable_label = "paused" [clients."studio-zoe.pl"] google_ads_customer_id = "387-166-1050" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."aruba.rzeszow.pl"] 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/" seo_works_history_sheet = "https://docs.google.com/spreadsheets/d/1lle7nkl0ykkJMlo2eA8AuV7Sd705ia6bmh7RM38nsRg/" seo_links_history_sheet = "https://docs.google.com/spreadsheets/d/1b4uCBzNSFFxIv2X1fTsqZcdDr7NZZYOIsmc9kLJqkq0/" +skip_in_all = ["split_pla_cl1_bestsellers"] [clients."ibra-makeup.pl"] google_ads_customer_id = "818-919-2566" adspro_client_id = "4" sales_history_sheet = "https://docs.google.com/spreadsheets/d/1OGqRluQgd2vCVxbmVLhPd00q8RWucSc0L4GdcGAl8vU" +skip_in_all = ["split_pla_cl1_bestsellers"] [global_rules] max_create_groups_without_extra_confirm = 100 diff --git a/src/gads_v2/cli.py b/src/gads_v2/cli.py index b0dcc2a..f8a5355 100644 --- a/src/gads_v2/cli.py +++ b/src/gads_v2/cli.py @@ -113,6 +113,47 @@ def choose_index(label: str, options: list[str]) -> int | None: 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: if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="replace") @@ -307,9 +348,17 @@ def main() -> None: if args.select: selected = args.select.strip() if selected.upper() == "ALL": - run_task_sequence( + selected_tasks, skipped_tasks = tasks_for_all_selection( tasks, 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, plan_only=args.plan_only, ) @@ -365,9 +414,17 @@ def main() -> None: return if args.all_groups: - run_task_sequence( + selected_tasks, skipped_tasks = tasks_for_all_selection( tasks, 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, plan_only=args.plan_only, ) @@ -419,10 +476,12 @@ def main() -> None: return selected_tasks = [] + respect_all_skips = False if args.select: selected = args.select.strip() if selected.upper() == "ALL": selected_tasks = tasks + respect_all_skips = True else: selected_tasks = tasks_by_selection_group(tasks, groups, selected) if not selected_tasks: @@ -438,6 +497,7 @@ def main() -> None: return elif args.all_groups: selected_tasks = tasks + respect_all_skips = True elif args.task: selected_tasks = [task for task in tasks if task.id == args.task] if not selected_tasks: @@ -456,6 +516,7 @@ def main() -> None: domains, plan_only=True, pause_after_client=True, + respect_all_skips=respect_all_skips, ) return @@ -1762,6 +1823,7 @@ def run_tasks_for_all_clients( domains: list[str], plan_only: bool = True, pause_after_client: bool = True, + respect_all_skips: bool = False, ) -> None: total_clients = len(domains) total_tasks = len(tasks) @@ -1782,10 +1844,22 @@ def run_tasks_for_all_clients( print("#" * 72) print(f"Klient {client_index}/{total_clients}: {domain}") 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("-" * 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) try: run_task( diff --git a/src/gads_v2/config.py b/src/gads_v2/config.py index 4b9c7c0..7a48610 100644 --- a/src/gads_v2/config.py +++ b/src/gads_v2/config.py @@ -27,6 +27,7 @@ class ClientConfig: domain: str google_ads_customer_id: str adspro_client_id: str | None = None + skip_in_all: tuple[str, ...] = () rules: dict | None = None @property @@ -45,6 +46,18 @@ class AppConfig: 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: config_path = path or ROOT / "config" / "clients.toml" if not config_path.exists(): @@ -59,6 +72,7 @@ def load_config(path: Path | None = None) -> AppConfig: domain=domain, 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, + skip_in_all=_string_tuple(row.get("skip_in_all")), rules={key: value for key, value in row.items() if isinstance(value, dict)}, ) return AppConfig(clients=clients, global_rules=data.get("global_rules", {}))