diff --git a/.claude/commands/wygeneruj-projekty.md b/.claude/commands/wygeneruj-projekty.md index 10dc0cf..3b88990 100644 --- a/.claude/commands/wygeneruj-projekty.md +++ b/.claude/commands/wygeneruj-projekty.md @@ -15,7 +15,7 @@ Użyj `"C:/xampp/mysql/bin/mysql.exe"` do zapytań (z flagą `--default-characte ### 2. Pobierz aktywne mapowania ```sql -SELECT id, product_name_pattern, script_name, output_dir +SELECT id, product_name_pattern, script_name, output_dir, requires_photo FROM project_mappings WHERE is_active = 1; ``` @@ -46,14 +46,16 @@ SELECT o.internal_order_number, o.status_code AS status_code, oa.name AS buyer_name, + oa.email AS buyer_email, pm.script_name, - pm.output_dir + pm.output_dir, + pm.requires_photo FROM order_items oi JOIN orders o ON oi.order_id = o.id JOIN order_statuses os ON o.status_code = os.code JOIN order_status_groups osg ON os.group_id = osg.id JOIN project_mappings pm ON pm.is_active = 1 - AND oi.original_name LIKE CONCAT('%', pm.product_name_pattern, '%') + AND oi.original_name = pm.product_name_pattern LEFT JOIN order_addresses oa ON o.id = oa.order_id AND oa.address_type = 'customer' WHERE osg.id = 2 AND oi.project_generated = 0 @@ -93,9 +95,31 @@ tasklist //FI "IMAGENAME eq Photoshop.exe" 2>/dev/null | grep -i photoshop ``` Jeśli Photoshop nie jest uruchomiony — poinformuj użytkownika i poczekaj aż go uruchomi. +**Pobranie zdjęcia od klienta (jeśli `requires_photo = 1`):** + +Dla mapowań z `requires_photo = 1` przed wywołaniem generatora pobierz zdjęcie z poczty klienta: +```bash +python tools/generowanie/email_photo_fetcher.py --email "{buyer_email}" --out "C:/tmp/orderpro_photos" --days 365 +``` +- Skrypt zwraca ścieżkę pobranego pliku albo komunikat `BRAK` (exit code 1). +- Jeśli zdjęcie się pobrało — przekaż ścieżkę do generatora przez `--zdjecie`. +- Jeśli zdjęcia **nie znaleziono** — generator i tak ma być wywołany **bez** `--zdjecie` (wstawi zielony placeholder jako sygnał "klient nie przysłał foto"). NIE blokuj generacji. +- Zaraportuj w tabeli planu (kolumna "Zdjęcie") status: ścieżka / `BRAK (zielony placeholder)`. + +**WAŻNE — rozpoznawanie płci dziecka (dla skryptów z parametrem `--plec`):** +Niektóre skrypty (np. `akrylowe_podziekowanie_matka_chrzestna_wzor2.py`) mają dwa warianty szablonu (chłopiec/dziewczynka) i wymagają parametru `--plec m` lub `--plec k`. Rozpoznaj płeć na podstawie personalizacji: +- **Imię proste** (Fabian, Wojciech, Kacper → `m`; Blanka, Zosia, Wiktoria → `k`) — standardowa wiedza o polskich imionach. +- **Imię odmienione** (np. "Wojtusia", "Kacpra" → `m`; "Blanki", "Zosi", "Wiktorii" → `k`) — rozpoznaj mianownik i z niego określ płeć. +- **Kontekst** — jeśli w personalizacji pojawia się "mój Chrześniak", "Drogi Synku", "malutki" → `m`; "moja Chrześniaczka", "Droga Córeczko", "malutka" → `k`. +- **W razie wątpliwości** — wyświetl surowe dane klientowi i zapytaj. + +**WAŻNE — łamanie linii w tekstach wielolinijkowych (życzenia, podziękowanie, itp.):** +Photoshop jako znak łamania linii w warstwach tekstowych rozpoznaje **`\r` (CR)**, NIE `\n` (LF). Jeśli przekażesz `\n`, Photoshop wyświetli go jako śmieciowy kwadrat z literą "n". W bashu użyj ANSI-C quoting: `$'linia1\rlinia2\rlinia3'` do budowy wartości `--zyczenia` / `--podziekowanie` i przekaż ją w cudzysłowach do skryptu. + Dla każdego potwierdzonego produktu: -1. Uruchom skrypt: `python tools/generowanie/{script_name} --imie_zenskie "X" --imie_meskie "Y" --data "DD.MM.YYYY" --klient "Imię Nazwisko"` (dodaj `--zyczenia` jeśli klient podał niestandardowe) -2. Jeśli mapowanie ma `output_dir` — skrypt powinien zapisać tam (jeśli obsługuje) +1. **Sprawdź kolizję nazwy pliku** w katalogu wyjściowym. Jeśli plik `{klient}.psd` (lub inne rozszerzenie używane przez skrypt) już istnieje — dodaj do nazwy klienta sufiks z indeksem `01`, `02`, ... (np. `Anna Rak` → `Anna Rak 01`, a jeśli i to zajęte → `Anna Rak 02`). Inkrementuj aż znajdziesz wolną nazwę. Dopiero wtedy przekaż wynik jako `--klient`. +2. Uruchom skrypt: `python tools/generowanie/{script_name} --klient "Imię Nazwisko" ...` (parametry zależne od skryptu — dla buteleczek/pudełek zwykle `--imie/--imiona`, `--data`, opcjonalnie `--zyczenia`/`--podziekowanie`; dla produktów ze zdjęciem dorzuć `--zdjecie /sciezka/do/foto.jpg`) +3. Jeśli mapowanie ma `output_dir` — skrypt powinien zapisać tam (jeśli obsługuje) ### 8. Oznacz w bazie diff --git a/.env b/.env index d530ba2..6f0be6b 100644 --- a/.env +++ b/.env @@ -24,4 +24,12 @@ pracownia.key=9554daf4bbcbbb5e72a2b48ee7d6a7f20262713d72484b781460e2c772d813fc ALLEGRO_USER_AGENT_URL=https://orderpro.pl/info login=jacek.pyziak@project-pro.pl -password=ProjectPro2025! \ No newline at end of file +password=ProjectPro2025! + +EMAIL_01_HOST = host700513.hostido.net.pl +EMAIL_01_PORT = 465 +EMAIL_01_USERNAME = sklep@pomysloweprezenty.pl +EMAIL_01_PASSWORD = Legia1916Warszawa +EMAIL_01_ENCRYPTION = ssl +EMAIL_01_IMAP_PORT = 993 +EMAIL_01_IMAP_FOLDER = INBOX \ No newline at end of file diff --git a/.paul/governance/governance_2026-04-12.jsonl b/.paul/governance/governance_2026-04-12.jsonl index 3cbdf79..f657bd4 100644 --- a/.paul/governance/governance_2026-04-12.jsonl +++ b/.paul/governance/governance_2026-04-12.jsonl @@ -186,3 +186,118 @@ {"ts":"2026-04-12T08:16:40Z","tool":"Bash","cmd":"rm \"C:/visual studio code/projekty/orderPRO/tools/generowanie/_debug_tmp.py\" && cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_wzor4.py --imie_zenskie \"W","cwd":"/c/visual studio code/projekty/orderPRO"} {"ts":"2026-04-12T08:16:55Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_wzor4.py --imie_zenskie \"Adrianna\" --imie_meskie \"Adam\" --data \"18.07.2026\" --klient \"Adrianna Bujnows","cwd":"/c/visual studio code/projekty/orderPRO"} {"ts":"2026-04-12T08:17:37Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && \"C:/xampp/php/php.exe\" -r \"\\\\$p=new PDO('mysql:host=host700513.hostido.net.pl;dbname=host700513_orderpro;charset=utf8mb4','host700513_orderpro','","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:02:40Z","tool":"Bash","cmd":"tasklist //FI \"IMAGENAME eq Photoshop.exe\" 2>/dev/null | grep -i photoshop; ls \"d:/pomysloweprezenty.pl/projekty/komunia święta - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ko","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:02:48Z","tool":"Bash","cmd":"tasklist //FI \"IMAGENAME eq Photoshop.exe\" 2>&1 | tail -3\",\"description\":\"Check Photoshop process\"},\"tool_response\":{\"stdout\":\"INFO: No tasks are running which match the specified criteria","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:03:01Z","tool":"Bash","cmd":"powershell -Command \"Get-ChildItem 'C:\\\\Program Files\\\\Adobe' -Directory | Select-Object -ExpandProperty Name\"\",\"description\":\"List Adobe folders\"},\"tool_response\":{\"stdout\":\"Adobe Cre","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:03:19Z","tool":"Bash","cmd":"powershell -Command \"Start-Process 'C:\\\\Program Files\\\\Adobe\\\\Adobe Photoshop 2026\\\\Photoshop.exe'; Start-Sleep -Seconds 8; (Get-Process Photoshop -ErrorAction SilentlyContinue).Count\"\",\"d","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:03:32Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_explore_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:03:40Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1\",\"description\":\"Run PSD explore script\"},\"tool_response\":{\"stdout\":\"DOC: pude�ka na chrzest","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:07:07Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:07:19Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -30\",\"description\":\"Rename PSD layers and save\"},\"tool_response\":{\"stdout\":\"RENAME OK +","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:08:06Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_chlopiec.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:08:16Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_komunia_chlopiec.py --klient \"TEST_Maciek\" --imie \"Maciek\" --data \"10.05.2026\" --od-kogo \"Rodzice Chrzestni\" ","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:08:21Z","tool":"Bash","cmd":"rm \"C:/visual studio code/projekty/orderPRO/tools/generowanie/_explore_temp.py\" \"C:/visual studio code/projekty/orderPRO/tools/generowanie/_rename_temp.py\"\",\"description\":\"Clean up temp script","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:13:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_chlopiec.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:13:22Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_chlopiec.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:13:34Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_komunia_chlopiec.py --klient \"TEST_Maciek\" --imie \"Maciek\" --data \"10.05.2026\" --od-kogo \"Rodzice Chrzestni\" ","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:13:54Z","tool":"Write","file":"C:\\\\Users\\\\jacek\\\\.claude\\\\projects\\\\C--visual-studio-code-projekty-orderPRO\\\\memory\\\\feedback_photoshop_text_centered.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:14:04Z","tool":"Edit","file":"C:\\\\Users\\\\jacek\\\\.claude\\\\projects\\\\C--visual-studio-code-projekty-orderPRO\\\\memory\\\\MEMORY.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:15:02Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_chlopiec.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:15:16Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_komunia_chlopiec.py --klient \"TEST_Maciek\" --imie \"Maciek\" --data \"10.05.2026\" --od-kogo \"Rodzice Chrzestni\" ","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:15:42Z","tool":"Edit","file":"C:\\\\Users\\\\jacek\\\\.claude\\\\projects\\\\C--visual-studio-code-projekty-orderPRO\\\\memory\\\\feedback_photoshop_text_centered.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:17:30Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && grep -E \"^DB_(HOST_REMOTE|DATABASE|USERNAME|PASSWORD|PORT)\" .env\",\"description\":\"Read DB credentials\"},\"tool_response\":{\"stdout\":\"DB_HOST_","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:17:38Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SELECT id, product_name_pat","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:17:53Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SELECT oi.id AS item_id, o.","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:19:23Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_komunia_chlopiec.py --klient \"Agnieszka Stachyra\" --imie \"Fabiana\" --data \"31.05.2026\" --od-kogo \"życzy wujek","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:19:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_komunia_chlopiec.py --klient \"Izabela Wenecka\" --imie \"Doriana\" --data \"21.06.2026\" --od-kogo \"Ciocia Izabela\","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:21:25Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"UPDATE order_items SET proj","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:23:24Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_explore_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:23:30Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1\",\"description\":\"Explore girl PSD\"},\"tool_response\":{\"stdout\":\"DOC: pude�ka na chrzest - mak","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:25:15Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:25:28Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -25\",\"description\":\"Rename girl PSD layers\"},\"tool_response\":{\"stdout\":\"RENAME OK + SAV","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:26:02Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_pudelko_komunia_core.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:26:13Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_chlopiec.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:26:21Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_dziewczynka.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:36:00Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1\",\"description\":\"Explore chrzest dziewczynka PSD\"},\"tool_response\":{\"stdout\":\"DOC: pude�ka n","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:38:50Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:39:03Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -25\",\"description\":\"Rename layers\"},\"tool_response\":{\"stdout\":\"--- KP ---\\r\\nTXT: \"d","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:39:35Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_chrzest_dziewczynka_aniolek.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:39:46Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py --klient \"TEST_Lenka\" --imie \"Lenka\" --data \"19.04.2026\" --od-kogo \"Babcia Anna","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:40:51Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SELECT oi.id AS item_id, o.","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:42:16Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py --klient \"Aneta Krzysztoń\" --imie \"Leny\" --data \"19.04.2026\" --od-kogo \"Babcia","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:42:30Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py --klient \"Karolina Rynecka-Betlejewska\" --imie \"Agaty\" --data \"19.04.2026\" --od-","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:43:26Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"UPDATE order_items SET proj","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:44:38Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_explore_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:44:44Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1\",\"description\":\"Explore buteleczka młoda para\"},\"tool_response\":{\"stdout\":\"DOC: szablon 370x","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:44:59Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_explore_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:45:06Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1 | tail -40\",\"description\":\"Re-explore including kind 17\"},\"tool_response\":{\"stdout\":\"DOC: sza","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:46:40Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:46:49Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -10\",\"description\":\"Rename layers in SO\"},\"tool_response\":{\"stdout\":\"Inside SO: Warstwa","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:47:18Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\buteleczki_slub_mloda_para.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:47:27Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_mloda_para.py --klient \"TEST_MartynaPatryk\" --imiona \"Martyna i Patryk\" --data \"06.06.2026\" 2>&1 | tail","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:49:07Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SELECT oi.id AS item_id, o.","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:50:22Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_mloda_para.py --klient \"Julia Krawczyk\" --imiona \"Honorata i Adam\" --data \"30.05.2026\" 2>&1 | tail -3\"","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:50:32Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_mloda_para.py --klient \"Aldona Kołtuniewska\" --imiona \"Aldona i Norbert\" --data \"25.04.2026\" 2>&1 | ta","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T17:50:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/buteleczki_slub_mloda_para.py --klient \"Ola Wiewióra\" --imiona \"Aleksandra & Piotr\" --data \"26.06.2026\" 2>&1 | tail -3","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:07:58Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"UPDATE order_items SET proj","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:09:02Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_explore_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:09:09Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_explore_temp.py 2>&1\",\"description\":\"Explore akrylowe podziekowanie\"},\"tool_response\":{\"stdout\":\"DOC: Akrylowe pod","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:16:59Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:17:05Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -15\",\"description\":\"Rename + convert to SO\"},\"tool_response\":{\"stdout\":\"Traceback (most","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:17:10Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\_rename_temp.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:17:15Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/_rename_temp.py 2>&1 | tail -15\",\"description\":\"Retry rename + SO\"},\"tool_response\":{\"stdout\":\"Konwertowano: kind=5","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:17:22Z","tool":"Bash","cmd":"python -c \"from PIL import Image; print('Pillow OK', Image.__version__ if hasattr(Image,'__version__') else 'installed')\" 2>&1\",\"description\":\"Check Pillow availability\"},\"tool_response\":{\"s","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:18:04Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\akrylowe_podziekowanie_matka_chrzestna_wzor1.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:18:11Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"TEST_no_photo\" --imie \"Gabrysia\" --data \"21.09.2025\" 2>&1 | t","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:19:02Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\email_photo_fetcher.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:20:19Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\email_photo_fetcher.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:20:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\email_photo_fetcher.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:20:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\email_photo_fetcher.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:21:11Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.env","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:21:20Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/email_photo_fetcher.py --email andzelikabaranska123@o2.pl --out C:/tmp/orderpro_photos --days 365 2>&1\",\"description\":\"Te","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:21:35Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"TEST_with_photo\" --imie \"Andżelika\" --data \"21.09.2025\" --zd","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:21:42Z","tool":"Bash","cmd":"rm \"C:/visual studio code/projekty/orderPRO/tools/generowanie/_explore_temp.py\" \"C:/visual studio code/projekty/orderPRO/tools/generowanie/_rename_temp.py\"\",\"description\":\"Cleanup temp scripts","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:06Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\database\\\\migrations\\\\20260412_000099_add_requires_photo_to_project_mappings.sql","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:14Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 < \"C:/visual studio code/projek","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:25Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\src\\\\Modules\\\\Settings\\\\ProjectMappingRepository.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:34Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\src\\\\Modules\\\\Settings\\\\ProjectMappingController.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:42Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\src\\\\Modules\\\\Settings\\\\ProjectMappingController.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:24:53Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\database\\\\migrations\\\\20260412_000099_add_requires_photo_to_project_mappings.sql","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:02Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SHOW TABLES LIKE 'migration","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:08Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"DESCRIBE migrations; SELECT","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:19Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:24Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:35Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:41Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\views\\\\settings\\\\project-mappings.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:25:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\resources\\\\lang\\\\pl.php","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:26:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:26:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:26:31Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SHOW COLUMNS FROM order_add","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:26:55Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:27:04Z","tool":"Bash","cmd":"php -l \"C:/visual studio code/projekty/orderPRO/resources/views/settings/project-mappings.php\" && php -l \"C:/visual studio code/projekty/orderPRO/src/Modules/Settings/ProjectMappingRepository.php\"","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:27:50Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"SELECT oi.id AS item_id, o.","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:30:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\email_photo_fetcher.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:30:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"Natalia Starzec\" --imie \"Wiktoria\" --data \"18.04.2026\" --zdje","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:30:56Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"Anna Rak\" --imie \"Franio\" --data \"19.04.2026\" --zdjecie \"C:/","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:31:12Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"Andżelika Barańska\" --imie \"Antoś\" --data \"25.04.2026\" --z","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:31:23Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"Kinga Giertuga\" --imie \"Julian\" --data \"26|04|2026\" --podziek","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:31:33Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/orderPRO\" && python tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py --klient \"Łukasz Malicki\" --imie \"Laura\" --data \"04.07.2026\" --podziek","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:32:43Z","tool":"Bash","cmd":"\"C:/xampp/mysql/bin/mysql.exe\" -h host700513.hostido.net.pl -P 3306 -u host700513_orderpro -phrDNtUBg9grwZ7syN77S host700513_orderpro --default-character-set=utf8mb4 -e \"UPDATE order_items SET proj","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:33:54Z","tool":"Bash","cmd":"tasklist //FI \"IMAGENAME eq Photoshop.exe\" 2>/dev/null | grep -i photoshop; ls \"d:/pomysloweprezenty.pl/projekty/chrzest - podziękowania/Akrylowe podziękowanie na chrzest dla Ojca Chrzestnego - W","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:41:36Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\akrylowe_podziekowanie_ojciec_chrzestny_wzor1.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:45:12Z","tool":"Bash","cmd":"tasklist //FI \"IMAGENAME eq Photoshop.exe\" | grep -i photoshop\",\"description\":\"Check Photoshop running\"},\"tool_response\":{\"stdout\":\"Binary file (standard input) matches\",\"stderr\":\"\",\","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:47:41Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T18:54:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:00:54Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_komunia_kwiaty.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:06:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:12:23Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\akrylowe_podziekowanie_matka_chrzestna_wzor2.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:13:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.claude\\\\commands\\\\wygeneruj-projekty.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:18:47Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_chrzest_golabek.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:20:02Z","tool":"Bash","cmd":"mv \"C:/visual studio code/projekty/orderPRO/tools/generowanie/pudelko_chrzest_golabek.py\" \"C:/visual studio code/projekty/orderPRO/tools/generowanie/pudelko_chrzest_golabek_hdf.py\"\",\"description","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:23:39Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\pudelko_chrzest_golabek_uv.py","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:26:23Z","tool":"Write","file":"C:\\\\Users\\\\jacek\\\\.claude\\\\projects\\\\C--visual-studio-code-projekty-orderPRO\\\\memory\\\\feedback_table_summaries.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:26:38Z","tool":"Edit","file":"C:\\\\Users\\\\jacek\\\\.claude\\\\projects\\\\C--visual-studio-code-projekty-orderPRO\\\\memory\\\\MEMORY.md","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:33:17Z","tool":"Bash","cmd":"tasklist //FI \"IMAGENAME eq Photoshop.exe\" 2>/dev/null | grep -i photoshop || echo \"NOT_RUNNING\"\",\"description\":\"Check if Photoshop is running\"},\"tool_response\":{\"stdout\":\"Binary file (s","cwd":"/c/visual studio code/projekty/orderPRO"} +{"ts":"2026-04-12T19:36:48Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\tools\\\\generowanie\\\\akrylowa_statuetka_podziekowanie_rodzice_wzor1.py","cwd":"/c/visual studio code/projekty/orderPRO"} diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 2d17420..07c90e6 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -3519,7 +3519,7 @@ "ProjectMappingController.php": { "type": "-", "size": 5761, - "lmtime": 1775947286124, + "lmtime": 1775981283053, "modified": false }, "ProjectMappingRepository.php": { @@ -5630,250 +5630,6 @@ } } }, - "tools": { - "apaczka_probe_order.php": { - "type": "-", - "size": 16643, - "lmtime": 1773006858881, - "modified": true - }, - "debug_inspect_shoppro_payload.php": { - "type": "-", - "size": 1382, - "lmtime": 1772994379240, - "modified": false - }, - "debug_order13_shoppro.php": { - "type": "-", - "size": 3079, - "lmtime": 1772995518963, - "modified": false - }, - "debug_order16_shoppro_payload.php": { - "type": "-", - "size": 3045, - "lmtime": 1772997478436, - "modified": false - }, - "debug_remote_product_tables.php": { - "type": "-", - "size": 2693, - "lmtime": 1772996712664, - "modified": false - }, - "debug_shoppro_api_list.php": { - "type": "-", - "size": 2733, - "lmtime": 1772996974868, - "modified": false - }, - "debug_shoppro_list_fields.php": { - "type": "-", - "size": 4359, - "lmtime": 1772997011189, - "modified": false - }, - "force_shoppro_resync.php": { - "type": "-", - "size": 2217, - "lmtime": 1772995312041, - "modified": false - }, - "komunia_blanki_CMYK.tiff": { - "type": "-", - "size": 4117074, - "lmtime": 0, - "modified": false - }, - "krita_komunia_template.py": { - "type": "-", - "size": 7065, - "lmtime": 0, - "modified": false - }, - "ps3A5F.tmp": { - "type": "-", - "size": 12738987, - "lmtime": 0, - "modified": false - }, - "ps41B1.tmp": { - "type": "-", - "size": 12415665, - "lmtime": 0, - "modified": false - }, - "ps46F3.tmp": { - "type": "-", - "size": 0, - "lmtime": 0, - "modified": false - }, - "ps6925.tmp": { - "type": "-", - "size": 12415621, - "lmtime": 0, - "modified": false - }, - "ps7EB2.tmp": { - "type": "-", - "size": 0, - "lmtime": 0, - "modified": false - }, - "ps84AA.tmp": { - "type": "-", - "size": 12415613, - "lmtime": 0, - "modified": false - }, - "ps91CA.tmp": { - "type": "-", - "size": 0, - "lmtime": 0, - "modified": false - }, - "psd_personalize.py": { - "type": "-", - "size": 42084, - "lmtime": 1774652966314, - "modified": false - }, - "resync_shoppro_6_once.php": { - "type": "-", - "size": 2930, - "lmtime": 1772997456426, - "modified": false - }, - "resync_shoppro_integration6.php": { - "type": "-", - "size": 2931, - "lmtime": 1772997216317, - "modified": false - }, - "run_shoppro_forced_sync.php": { - "type": "-", - "size": 5207, - "lmtime": 1772995390145, - "modified": false - }, - "run_shoppro_resync_and_check.php": { - "type": "-", - "size": 3809, - "lmtime": 1772997027491, - "modified": false - }, - "run_shoppro_resync_once.php": { - "type": "-", - "size": 3118, - "lmtime": 1772995715104, - "modified": false - }, - "tmp_apaczka_diag.php": { - "type": "-", - "size": 3270, - "lmtime": 1773005813641, - "modified": false - }, - "tmp_debug_invoice21.php": { - "type": "-", - "size": 2120, - "lmtime": 1773005262378, - "modified": false - }, - "tmp_debug_mappings.php": { - "type": "-", - "size": 1031, - "lmtime": 1773004603276, - "modified": false - }, - "tmp_debug_order21.php": { - "type": "-", - "size": 2713, - "lmtime": 1773004581202, - "modified": false - }, - "tmp_desc_addr.php": { - "type": "-", - "size": 63, - "lmtime": 1773005271225, - "modified": true - }, - "tmp_fix_invoice_order21.php": { - "type": "-", - "size": 73, - "lmtime": 1773005509575, - "modified": true - }, - "tmp_inpost_point.php": { - "type": "-", - "size": 1419, - "lmtime": 1773006337485, - "modified": false - }, - "tmp_inpost_services.php": { - "type": "-", - "size": 1652, - "lmtime": 1773006307738, - "modified": false - }, - "tmp_invoice_values.php": { - "type": "-", - "size": 68, - "lmtime": 1773005292209, - "modified": true - }, - "tmp_pkg21.php": { - "type": "-", - "size": 59, - "lmtime": 1773005863375, - "modified": true - }, - "tmp_points.php": { - "type": "-", - "size": 1623, - "lmtime": 1773006323287, - "modified": false - }, - "tmp_probe_more.php": { - "type": "-", - "size": 3601, - "lmtime": 1773006699957, - "modified": false - }, - "tmp_probe_ups.php": { - "type": "-", - "size": 2590, - "lmtime": 1773006737809, - "modified": false - }, - "generowanie": { - "buteleczki_wzor1.py": { - "type": "-", - "size": 4723, - "lmtime": 1775946288094, - "modified": false - }, - "buteleczki_wzor6.py": { - "type": "-", - "size": 4841, - "lmtime": 1775950147593, - "modified": false - }, - "buteleczki_wzor8.py": { - "type": "-", - "size": 5265, - "lmtime": 1775949133934, - "modified": false - }, - "tmp_mapping.sql": { - "type": "-", - "size": 225, - "lmtime": 1775950247575, - "modified": false - } - } - }, "vendor": { "autoload.php": { "type": "-", @@ -5977,6 +5733,40 @@ "phpmailer": { "phpmailer": {} } + }, + "tools": { + "generowanie": { + "buteleczki_slub_wzor1.py": { + "type": "-", + "size": 4723, + "lmtime": 0, + "modified": false + }, + "buteleczki_slub_wzor4.py": { + "type": "-", + "size": 5304, + "lmtime": 1775981774924, + "modified": false + }, + "buteleczki_slub_wzor6.py": { + "type": "-", + "size": 4841, + "lmtime": 1775950147593, + "modified": false + }, + "buteleczki_slub_wzor8.py": { + "type": "-", + "size": 5265, + "lmtime": 1775949133934, + "modified": false + }, + "_debug_tmp.py": { + "type": "-", + "size": 1316, + "lmtime": 1775981736922, + "modified": false + } + } } } }, diff --git a/database/migrations/20260412_000099_add_requires_photo_to_project_mappings.sql b/database/migrations/20260412_000099_add_requires_photo_to_project_mappings.sql new file mode 100644 index 0000000..524eb27 --- /dev/null +++ b/database/migrations/20260412_000099_add_requires_photo_to_project_mappings.sql @@ -0,0 +1,2 @@ +ALTER TABLE project_mappings + ADD COLUMN IF NOT EXISTS requires_photo TINYINT(1) NOT NULL DEFAULT 0 AFTER output_dir; diff --git a/resources/lang/pl.php b/resources/lang/pl.php index d3d9221..79f02f5 100644 --- a/resources/lang/pl.php +++ b/resources/lang/pl.php @@ -1135,6 +1135,7 @@ return [ 'pattern' => 'Wzorzec nazwy produktu', 'script' => 'Skrypt generujacy', 'output_dir' => 'Katalog wyjsciowy', + 'requires_photo' => 'Wymaga zdjecia', 'active' => 'Status', 'actions' => 'Akcje', ], diff --git a/resources/views/settings/project-mappings.php b/resources/views/settings/project-mappings.php index cf6f046..d9895c3 100644 --- a/resources/views/settings/project-mappings.php +++ b/resources/views/settings/project-mappings.php @@ -41,6 +41,14 @@ $scripts = is_array($scripts ?? null) ? $scripts : []; + +
@@ -60,6 +68,7 @@ $scripts = is_array($scripts ?? null) ? $scripts : []; + @@ -70,6 +79,7 @@ $scripts = is_array($scripts ?? null) ? $scripts : []; +
@@ -83,7 +93,8 @@ $scripts = is_array($scripts ?? null) ? $scripts : []; data-id="" data-pattern="" data-script="" - data-output-dir=""> + data-output-dir="" + data-requires-photo=""> @@ -146,6 +164,7 @@ document.addEventListener('DOMContentLoaded', function() { form.querySelector('[name="product_name_pattern"]').value = this.dataset.pattern; form.querySelector('[name="script_name"]').value = this.dataset.script; form.querySelector('[name="output_dir"]').value = this.dataset.outputDir || ''; + form.querySelector('[name="requires_photo"]').checked = this.dataset.requiresPhoto === '1'; modal.style.display = 'flex'; }); }); @@ -156,22 +175,31 @@ document.addEventListener('DOMContentLoaded', function() { }); }); + function submitDelete(id, token) { + var f = document.createElement('form'); + f.method = 'post'; + f.action = '/settings/project-mappings/' + id + '/delete'; + var t = document.createElement('input'); + t.type = 'hidden'; t.name = '_token'; t.value = token; + f.appendChild(t); + document.body.appendChild(f); + f.submit(); + } + document.querySelectorAll('.js-pm-delete').forEach(function(btn) { btn.addEventListener('click', function() { var id = this.dataset.id; var token = this.dataset.token; - if (typeof window.OrderProAlerts !== 'undefined') { - window.OrderProAlerts.confirm('', function() { - var f = document.createElement('form'); - f.method = 'post'; - f.action = '/settings/project-mappings/' + id + '/delete'; - var t = document.createElement('input'); - t.type = 'hidden'; t.name = '_token'; t.value = token; - f.appendChild(t); - document.body.appendChild(f); - f.submit(); - }); + if (!window.OrderProAlerts || typeof window.OrderProAlerts.confirm !== 'function') { + return; } + window.OrderProAlerts.confirm({ + title: '', + message: '', + danger: true + }).then(function(confirmed) { + if (confirmed) submitDelete(id, token); + }); }); }); }); diff --git a/src/Modules/Settings/ProjectMappingController.php b/src/Modules/Settings/ProjectMappingController.php index 0aebea1..30a79a6 100644 --- a/src/Modules/Settings/ProjectMappingController.php +++ b/src/Modules/Settings/ProjectMappingController.php @@ -55,6 +55,7 @@ final class ProjectMappingController $pattern = trim((string) $request->input('product_name_pattern', '')); $scriptName = trim((string) $request->input('script_name', '')); $outputDir = trim((string) $request->input('output_dir', '')); + $requiresPhoto = (string) $request->input('requires_photo', '') !== ''; if ($pattern === '' || $scriptName === '') { Flash::set('settings_error', $this->translator->get('settings.project_mapping.flash.validation_error')); @@ -71,6 +72,7 @@ final class ProjectMappingController 'product_name_pattern' => $pattern, 'script_name' => $scriptName, 'output_dir' => $outputDir !== '' ? $outputDir : null, + 'requires_photo' => $requiresPhoto ? 1 : 0, ]); Flash::set('settings_success', $this->translator->get('settings.project_mapping.flash.created')); @@ -88,6 +90,7 @@ final class ProjectMappingController $pattern = trim((string) $request->input('product_name_pattern', '')); $scriptName = trim((string) $request->input('script_name', '')); $outputDir = trim((string) $request->input('output_dir', '')); + $requiresPhoto = (string) $request->input('requires_photo', '') !== ''; if ($id <= 0 || $pattern === '' || $scriptName === '') { Flash::set('settings_error', $this->translator->get('settings.project_mapping.flash.validation_error')); @@ -98,6 +101,7 @@ final class ProjectMappingController 'product_name_pattern' => $pattern, 'script_name' => $scriptName, 'output_dir' => $outputDir !== '' ? $outputDir : null, + 'requires_photo' => $requiresPhoto ? 1 : 0, ]); Flash::set('settings_success', $this->translator->get('settings.project_mapping.flash.updated')); diff --git a/src/Modules/Settings/ProjectMappingRepository.php b/src/Modules/Settings/ProjectMappingRepository.php index 8ea6557..40efdf5 100644 --- a/src/Modules/Settings/ProjectMappingRepository.php +++ b/src/Modules/Settings/ProjectMappingRepository.php @@ -37,13 +37,14 @@ final class ProjectMappingRepository public function create(array $data): int { $statement = $this->pdo->prepare( - 'INSERT INTO project_mappings (product_name_pattern, script_name, output_dir, is_active) - VALUES (:product_name_pattern, :script_name, :output_dir, :is_active)' + 'INSERT INTO project_mappings (product_name_pattern, script_name, output_dir, requires_photo, is_active) + VALUES (:product_name_pattern, :script_name, :output_dir, :requires_photo, :is_active)' ); $statement->execute([ ':product_name_pattern' => $data['product_name_pattern'], ':script_name' => $data['script_name'], ':output_dir' => $data['output_dir'] ?? null, + ':requires_photo' => (int) ($data['requires_photo'] ?? 0), ':is_active' => (int) ($data['is_active'] ?? 1), ]); @@ -56,7 +57,8 @@ final class ProjectMappingRepository 'UPDATE project_mappings SET product_name_pattern = :product_name_pattern, script_name = :script_name, - output_dir = :output_dir + output_dir = :output_dir, + requires_photo = :requires_photo WHERE id = :id' ); @@ -64,6 +66,7 @@ final class ProjectMappingRepository ':product_name_pattern' => $data['product_name_pattern'], ':script_name' => $data['script_name'], ':output_dir' => $data['output_dir'] ?? null, + ':requires_photo' => (int) ($data['requires_photo'] ?? 0), ':id' => $id, ]); } diff --git a/tools/generowanie/__pycache__/_pudelko_komunia_core.cpython-312.pyc b/tools/generowanie/__pycache__/_pudelko_komunia_core.cpython-312.pyc new file mode 100644 index 0000000..0e67f44 Binary files /dev/null and b/tools/generowanie/__pycache__/_pudelko_komunia_core.cpython-312.pyc differ diff --git a/tools/generowanie/_assets/green_placeholder.png b/tools/generowanie/_assets/green_placeholder.png new file mode 100644 index 0000000..d438aec Binary files /dev/null and b/tools/generowanie/_assets/green_placeholder.png differ diff --git a/tools/generowanie/_pudelko_komunia_core.py b/tools/generowanie/_pudelko_komunia_core.py new file mode 100644 index 0000000..ba1178f --- /dev/null +++ b/tools/generowanie/_pudelko_komunia_core.py @@ -0,0 +1,99 @@ +""" +Wspólny rdzeń dla generatorów PSD pudełek komunijnych (chłopiec/dziewczynka). + +Makieta A3 zawiera 4 grupy warstw (GL/GP/DL/DP) — 1 PSD = 1 zamówienie, +te same dane lecą do górnej i dolnej części makiety. Brak Smart Objectów, +teksty są bezpośrednio w grupach. Po normalizacji nazw (rename w PSD) wszystkie +warianty mają identyczną strukturę: od_kogo / naglowek / zyczenia / imie / data / tytul. +""" + +import argparse +import os +import photoshop.api as ps + + +ZYCZENIA_GROUPS = [ + ("GL", "dane"), + ("DL", None), +] +IMIE_GROUPS = [ + ("GP", "dane"), + ("DP", None), +] + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowując środek bounding boxa. + Photoshop API po zmianie textItem.contents resetuje pozycję warstwy do + punktu kotwiczenia, co dla tekstu wycentrowanego psuje layout. Liczymy + środek bounds przed/po i kompensujemy translacją.""" + b = [float(x) for x in layer.bounds] + cx_before = (b[0] + b[2]) / 2 + cy_before = (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx_after = (b2[0] + b2[2]) / 2 + cy_after = (b2[1] + b2[3]) / 2 + dx = cx_before - cx_after + dy = cy_before - cy_after + if dx or dy: + layer.translate(dx, dy) + + +def get_container(doc, set_name, inner_name): + container = doc.layerSets[set_name] + if inner_name: + container = container.layerSets[inner_name] + return container + + +def apply_replacements(container, replacements): + for layer_name, new_text in replacements.items(): + if new_text is None: + continue + layer = container.artLayers[layer_name] + old_text = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old_text}" -> "{new_text}"') + + +def generate(szablon_path, gotowe_dir, imie, data, od_kogo, klient, + zyczenia=None, naglowek=None, tytul=None): + """Generuje PSD z podmienionymi danymi (1 PSD = 1 zamówienie).""" + os.makedirs(gotowe_dir, exist_ok=True) + output_path = os.path.join(gotowe_dir, f"{klient}.psd") + + app = ps.Application() + doc = app.open(szablon_path) + print(f"Otwarto szablon: {doc.name}") + + zyczenia_map = {"od_kogo": od_kogo, "naglowek": naglowek, "zyczenia": zyczenia} + imie_map = {"imie": imie, "data": data, "tytul": tytul} + + for set_name, inner in ZYCZENIA_GROUPS: + print(f" [{set_name}] życzenia:") + apply_replacements(get_container(doc, set_name, inner), zyczenia_map) + + for set_name, inner in IMIE_GROUPS: + print(f" [{set_name}] imię/data:") + apply_replacements(get_container(doc, set_name, inner), imie_map) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def build_arg_parser(description): + parser = argparse.ArgumentParser(description=description) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego") + parser.add_argument("--imie", required=True, help="Imię dziecka") + parser.add_argument("--data", required=True, help="Data uroczystości (np. 10.05.2026)") + parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)") + parser.add_argument("--zyczenia", default=None, help="Treść życzeń (opcjonalnie, domyślnie z szablonu)") + parser.add_argument("--naglowek", default=None, help="Nagłówek życzeń (opcjonalnie, domyślnie z szablonu)") + parser.add_argument("--tytul", default=None, help="Tytuł (opcjonalnie, domyślnie z szablonu)") + return parser diff --git a/tools/generowanie/_tmp_photos/01_IMG_7330.jpeg b/tools/generowanie/_tmp_photos/01_IMG_7330.jpeg new file mode 100644 index 0000000..24a4b41 Binary files /dev/null and b/tools/generowanie/_tmp_photos/01_IMG_7330.jpeg differ diff --git a/tools/generowanie/_tmp_photos/02_IMG_7333.jpeg b/tools/generowanie/_tmp_photos/02_IMG_7333.jpeg new file mode 100644 index 0000000..3f7740d Binary files /dev/null and b/tools/generowanie/_tmp_photos/02_IMG_7333.jpeg differ diff --git a/tools/generowanie/_tmp_photos/03_IMG_7336.jpeg b/tools/generowanie/_tmp_photos/03_IMG_7336.jpeg new file mode 100644 index 0000000..186c5bd Binary files /dev/null and b/tools/generowanie/_tmp_photos/03_IMG_7336.jpeg differ diff --git a/tools/generowanie/akrylowa_statuetka_podziekowanie_rodzice_wzor1.py b/tools/generowanie/akrylowa_statuetka_podziekowanie_rodzice_wzor1.py new file mode 100644 index 0000000..9876bb7 --- /dev/null +++ b/tools/generowanie/akrylowa_statuetka_podziekowanie_rodzice_wzor1.py @@ -0,0 +1,179 @@ +""" +Generator PSD — Akrylowa statuetka podziekowanie dla Rodzicow ze zdjeciem (Wzor 1). + +Plaska struktura PSD: w "Warstwa 1" znajduja sie: +- warstwy tekstowe: naglowek, imiona, data, zyczenia +- 4 Smart Objecty ze zdjeciami: zdjecie_01, zdjecie_02, zdjecie_03, zdjecie_04 + +Podmiana zdjec: +- jesli --zdjecieN wskazuje na istniejacy plik graficzny → zostaje wstawione, + przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane +- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy + zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto + +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\ślub - podziękowania", + "Akrylowa statuetka podziękowanie dla rodziców ze zdjęciem - Wzór 1", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowa statuetka podziękowanie dla rodziców ze zdjęciem - Wzór 1.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + +ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets") +GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png") + +PHOTO_SLOTS = ("zdjecie_01", "zdjecie_02", "zdjecie_03", "zdjecie_04") + + +def ensure_green_placeholder(): + """Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia.""" + if os.path.exists(GREEN_PLACEHOLDER_PATH): + return GREEN_PLACEHOLDER_PATH + os.makedirs(ASSETS_DIR, exist_ok=True) + from PIL import Image + Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH) + return GREEN_PLACEHOLDER_PATH + + +def set_text(layer, new_text): + """Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy).""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def replace_smart_object_contents(app, file_path): + """Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO.""" + desc = ps.ActionDescriptor() + desc.putPath(app.charIDToTypeID("null"), file_path) + desc.putInteger(app.charIDToTypeID("PgNm"), 1) + app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc) + + +def replace_photo_cover(app, so_layer, photo_path): + """Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow.""" + target = [float(x) for x in so_layer.bounds] + target_w = target[2] - target[0] + target_h = target[3] - target[1] + target_cx = (target[0] + target[2]) / 2 + target_cy = (target[1] + target[3]) / 2 + + app.activeDocument.activeLayer = so_layer + replace_smart_object_contents(app, photo_path) + + new_b = [float(x) for x in so_layer.bounds] + new_w = new_b[2] - new_b[0] + new_h = new_b[3] - new_b[1] + if new_w <= 0 or new_h <= 0: + return + + scale = max(target_w / new_w, target_h / new_h) * 100.0 + so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter) + + cur = [float(x) for x in so_layer.bounds] + cur_cx = (cur[0] + cur[2]) / 2 + cur_cy = (cur[1] + cur[3]) / 2 + so_layer.translate(target_cx - cur_cx, target_cy - cur_cy) + + +def swap_photo_slot(app, container, slot_name, photo_path): + """Podmienia zdjecie w slocie; brak/nieistnieje → zielony placeholder.""" + so_layer = container.artLayers[slot_name] + if photo_path and os.path.isfile(photo_path): + print(f" {slot_name}: {photo_path}") + replace_photo_cover(app, so_layer, photo_path) + else: + if photo_path: + print(f" {slot_name}: UWAGA plik nie istnieje ({photo_path}) — zielony placeholder") + else: + print(f" {slot_name}: brak — zielony placeholder") + replace_photo_cover(app, so_layer, ensure_green_placeholder()) + + +def generate(klient, imiona, data, naglowek=None, zyczenia=None, + zdjecie1=None, zdjecie2=None, zdjecie3=None, zdjecie4=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + try: + w1 = doc.layerSets["Warstwa 1"] + + print(" Podmiana tekstow:") + set_layer_text(w1, "naglowek", naglowek) + set_layer_text(w1, "imiona", imiona) + set_layer_text(w1, "data", data) + set_layer_text(w1, "zyczenia", zyczenia) + + print(" Podmiana zdjec:") + zdjecia = [zdjecie1, zdjecie2, zdjecie3, zdjecie4] + for slot, photo in zip(PHOTO_SLOTS, zdjecia): + swap_photo_slot(app, w1, slot, photo) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + finally: + try: + doc.close(ps.SaveOptions.DoNotSaveChanges) + except Exception: + pass + + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - Akrylowa statuetka podziekowanie dla Rodzicow Wzor 1" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego (bez rozszerzenia)") + parser.add_argument("--imiona", required=True, help="Imiona pary mlodej (np. 'Kasia i Tomek')") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. '10.08.2025')") + parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochani Rodzice!')") + parser.add_argument("--zyczenia", default=None, help="Tresc podziekowania (opcjonalnie)") + parser.add_argument("--zdjecie1", default=None, help="Sciezka do zdjecia 1 (opcjonalnie; brak = zielony placeholder)") + parser.add_argument("--zdjecie2", default=None, help="Sciezka do zdjecia 2") + parser.add_argument("--zdjecie3", default=None, help="Sciezka do zdjecia 3") + parser.add_argument("--zdjecie4", default=None, help="Sciezka do zdjecia 4") + + args = parser.parse_args() + generate( + klient=args.klient, + imiona=args.imiona, + data=args.data, + naglowek=args.naglowek, + zyczenia=args.zyczenia, + zdjecie1=args.zdjecie1, + zdjecie2=args.zdjecie2, + zdjecie3=args.zdjecie3, + zdjecie4=args.zdjecie4, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py b/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py new file mode 100644 index 0000000..6858ab0 --- /dev/null +++ b/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor1.py @@ -0,0 +1,156 @@ +""" +Generator PSD — Akrylowe podziekowanie na chrzest dla Matki Chrzestnej (Wzór 1). + +Plaska struktura PSD: w "Warstwa 1" znajduja sie warstwy tekstowe +(imie, naglowek, podziekowanie, data) oraz Smart Object "zdjecie". + +Podmiana zdjecia: +- jesli --zdjecie wskazuje na istniejacy plik graficzny → zostaje wstawione, + przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane +- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy + zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto + +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania", + "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 1", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 1 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + +ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets") +GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png") + + +def ensure_green_placeholder(): + """Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia.""" + if os.path.exists(GREEN_PLACEHOLDER_PATH): + return GREEN_PLACEHOLDER_PATH + os.makedirs(ASSETS_DIR, exist_ok=True) + from PIL import Image + Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH) + return GREEN_PLACEHOLDER_PATH + + +def set_text(layer, new_text): + """Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy).""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def replace_smart_object_contents(app, file_path): + """Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO.""" + desc = ps.ActionDescriptor() + desc.putPath(app.charIDToTypeID("null"), file_path) + desc.putInteger(app.charIDToTypeID("PgNm"), 1) + app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc) + + +def replace_photo_cover(app, so_layer, photo_path): + """Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow.""" + target = [float(x) for x in so_layer.bounds] + target_w = target[2] - target[0] + target_h = target[3] - target[1] + target_cx = (target[0] + target[2]) / 2 + target_cy = (target[1] + target[3]) / 2 + + app.activeDocument.activeLayer = so_layer + replace_smart_object_contents(app, photo_path) + + new_b = [float(x) for x in so_layer.bounds] + new_w = new_b[2] - new_b[0] + new_h = new_b[3] - new_b[1] + if new_w <= 0 or new_h <= 0: + return + + scale = max(target_w / new_w, target_h / new_h) * 100.0 + so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter) + + cur = [float(x) for x in so_layer.bounds] + cur_cx = (cur[0] + cur[2]) / 2 + cur_cy = (cur[1] + cur[3]) / 2 + so_layer.translate(target_cx - cur_cx, target_cy - cur_cy) + + +def generate(klient, imie, data, zdjecie=None, naglowek=None, podziekowanie=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + w1 = doc.layerSets["Warstwa 1"] + + print(" Podmiana tekstow:") + set_layer_text(w1, "imie", imie) + set_layer_text(w1, "data", data) + set_layer_text(w1, "naglowek", naglowek) + set_layer_text(w1, "podziekowanie", podziekowanie) + + so_layer = w1.artLayers["zdjecie"] + if zdjecie and os.path.isfile(zdjecie): + print(f" Podmiana zdjecia: {zdjecie}") + replace_photo_cover(app, so_layer, zdjecie) + else: + if zdjecie: + print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder") + else: + print(" Brak --zdjecie — wstawiam zielony placeholder") + replace_photo_cover(app, so_layer, ensure_green_placeholder()) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - Akrylowe podziekowanie chrzest, Matka Chrzestna Wzor 1" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (np. Gabrysia)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 21.09.2025)") + parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia dziecka (opcjonalnie; brak = zielony placeholder)") + parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochana Matko Chrzestna')") + parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + zdjecie=args.zdjecie, + naglowek=args.naglowek, + podziekowanie=args.podziekowanie, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor2.py b/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor2.py new file mode 100644 index 0000000..784e3bd --- /dev/null +++ b/tools/generowanie/akrylowe_podziekowanie_matka_chrzestna_wzor2.py @@ -0,0 +1,168 @@ +""" +Generator PSD — Akrylowe podziekowanie na chrzest dla Matki Chrzestnej (Wzór 2). + +Dwa warianty szablonu (chlopiec / dziewczynka) wybierane parametrem --plec. +Oba PSD maja identyczna strukture warstw w "Warstwa 1": +imie, data, naglowek, tytul, podziekowanie oraz Smart Object "zdjecie". + +Podmiana zdjecia — jak w Wzorze 1: cover do oryginalnych boundsow, +zielony placeholder gdy brak zdjecia. + +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania", + "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2", +) +SZABLON_CHLOPIEC = os.path.join( + PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2 CMYK - chłopiec.psd" +) +SZABLON_DZIEWCZYNKA = os.path.join( + PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2 CMYK - dziewczynka.psd" +) +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + +ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets") +GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png") + + +def ensure_green_placeholder(): + if os.path.exists(GREEN_PLACEHOLDER_PATH): + return GREEN_PLACEHOLDER_PATH + os.makedirs(ASSETS_DIR, exist_ok=True) + from PIL import Image + Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH) + return GREEN_PLACEHOLDER_PATH + + +def set_text(layer, new_text): + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def replace_smart_object_contents(app, file_path): + desc = ps.ActionDescriptor() + desc.putPath(app.charIDToTypeID("null"), file_path) + desc.putInteger(app.charIDToTypeID("PgNm"), 1) + app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc) + + +def replace_photo_cover(app, so_layer, photo_path): + target = [float(x) for x in so_layer.bounds] + target_w = target[2] - target[0] + target_h = target[3] - target[1] + target_cx = (target[0] + target[2]) / 2 + target_cy = (target[1] + target[3]) / 2 + + app.activeDocument.activeLayer = so_layer + replace_smart_object_contents(app, photo_path) + + new_b = [float(x) for x in so_layer.bounds] + new_w = new_b[2] - new_b[0] + new_h = new_b[3] - new_b[1] + if new_w <= 0 or new_h <= 0: + return + + scale = max(target_w / new_w, target_h / new_h) * 100.0 + so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter) + + cur = [float(x) for x in so_layer.bounds] + cur_cx = (cur[0] + cur[2]) / 2 + cur_cy = (cur[1] + cur[3]) / 2 + so_layer.translate(target_cx - cur_cx, target_cy - cur_cy) + + +def generate(klient, imie, data, plec, zdjecie=None, naglowek=None, tytul=None, podziekowanie=None): + if plec == "m": + szablon_path = SZABLON_CHLOPIEC + elif plec == "k": + szablon_path = SZABLON_DZIEWCZYNKA + else: + raise ValueError(f"--plec musi byc 'm' lub 'k', otrzymano: {plec!r}") + + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(szablon_path) + print(f"Otwarto szablon: {doc.name}") + + w1 = doc.layerSets["Warstwa 1"] + + print(" Podmiana tekstow:") + set_layer_text(w1, "imie", imie) + set_layer_text(w1, "data", data) + set_layer_text(w1, "naglowek", naglowek) + set_layer_text(w1, "tytul", tytul) + set_layer_text(w1, "podziekowanie", podziekowanie) + + so_layer = w1.artLayers["zdjecie"] + if zdjecie and os.path.isfile(zdjecie): + print(f" Podmiana zdjecia: {zdjecie}") + replace_photo_cover(app, so_layer, zdjecie) + else: + if zdjecie: + print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder") + else: + print(" Brak --zdjecie — wstawiam zielony placeholder") + replace_photo_cover(app, so_layer, ensure_green_placeholder()) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - Akrylowe podziekowanie chrzest, Matka Chrzestna Wzor 2 (chlopiec/dziewczynka)" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (np. Wojtus, Blanka)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 19.04.2026)") + parser.add_argument("--plec", required=True, choices=["m", "k"], + help="Plec dziecka: 'm' = chlopiec, 'k' = dziewczynka") + parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia (opcjonalnie; brak = zielony placeholder)") + parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'MATKO CHRZESTNA')") + parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Dziękuję')") + parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + plec=args.plec, + zdjecie=args.zdjecie, + naglowek=args.naglowek, + tytul=args.tytul, + podziekowanie=args.podziekowanie, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/akrylowe_podziekowanie_ojciec_chrzestny_wzor1.py b/tools/generowanie/akrylowe_podziekowanie_ojciec_chrzestny_wzor1.py new file mode 100644 index 0000000..c05468c --- /dev/null +++ b/tools/generowanie/akrylowe_podziekowanie_ojciec_chrzestny_wzor1.py @@ -0,0 +1,156 @@ +""" +Generator PSD — Akrylowe podziekowanie na chrzest dla Ojca Chrzestnego (Wzór 1). + +Plaska struktura PSD: w "Warstwa 1" znajduja sie warstwy tekstowe +(imie, naglowek, podziekowanie, data) oraz Smart Object "zdjecie". + +Podmiana zdjecia: +- jesli --zdjecie wskazuje na istniejacy plik graficzny → zostaje wstawione, + przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane +- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy + zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto + +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania", + "Akrylowe podziękowanie na chrzest dla Ojca Chrzestnego - Wzór 1", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Ojca Chrzestnego - Wzór 1 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + +ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets") +GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png") + + +def ensure_green_placeholder(): + """Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia.""" + if os.path.exists(GREEN_PLACEHOLDER_PATH): + return GREEN_PLACEHOLDER_PATH + os.makedirs(ASSETS_DIR, exist_ok=True) + from PIL import Image + Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH) + return GREEN_PLACEHOLDER_PATH + + +def set_text(layer, new_text): + """Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy).""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def replace_smart_object_contents(app, file_path): + """Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO.""" + desc = ps.ActionDescriptor() + desc.putPath(app.charIDToTypeID("null"), file_path) + desc.putInteger(app.charIDToTypeID("PgNm"), 1) + app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc) + + +def replace_photo_cover(app, so_layer, photo_path): + """Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow.""" + target = [float(x) for x in so_layer.bounds] + target_w = target[2] - target[0] + target_h = target[3] - target[1] + target_cx = (target[0] + target[2]) / 2 + target_cy = (target[1] + target[3]) / 2 + + app.activeDocument.activeLayer = so_layer + replace_smart_object_contents(app, photo_path) + + new_b = [float(x) for x in so_layer.bounds] + new_w = new_b[2] - new_b[0] + new_h = new_b[3] - new_b[1] + if new_w <= 0 or new_h <= 0: + return + + scale = max(target_w / new_w, target_h / new_h) * 100.0 + so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter) + + cur = [float(x) for x in so_layer.bounds] + cur_cx = (cur[0] + cur[2]) / 2 + cur_cy = (cur[1] + cur[3]) / 2 + so_layer.translate(target_cx - cur_cx, target_cy - cur_cy) + + +def generate(klient, imie, data, zdjecie=None, naglowek=None, podziekowanie=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + w1 = doc.layerSets["Warstwa 1"] + + print(" Podmiana tekstow:") + set_layer_text(w1, "imie", imie) + set_layer_text(w1, "data", data) + set_layer_text(w1, "naglowek", naglowek) + set_layer_text(w1, "podziekowanie", podziekowanie) + + so_layer = w1.artLayers["zdjecie"] + if zdjecie and os.path.isfile(zdjecie): + print(f" Podmiana zdjecia: {zdjecie}") + replace_photo_cover(app, so_layer, zdjecie) + else: + if zdjecie: + print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder") + else: + print(" Brak --zdjecie — wstawiam zielony placeholder") + replace_photo_cover(app, so_layer, ensure_green_placeholder()) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - Akrylowe podziekowanie chrzest, Ojciec Chrzestny Wzor 1" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (np. Franek)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 26.10.2025)") + parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia dziecka (opcjonalnie; brak = zielony placeholder)") + parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochany Ojcze Chrzestny')") + parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + zdjecie=args.zdjecie, + naglowek=args.naglowek, + podziekowanie=args.podziekowanie, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/buteleczki_slub_mloda_para.py b/tools/generowanie/buteleczki_slub_mloda_para.py new file mode 100644 index 0000000..abe1b24 --- /dev/null +++ b/tools/generowanie/buteleczki_slub_mloda_para.py @@ -0,0 +1,126 @@ +""" +Generator PSD — Buteleczka ślubna "Młoda para". + +Szablon 370x300 to multi-up layout: 8 instancji Smart Object linkujących do +jednego źródła `Warstwa 1.psb`. Edycja źródła propaguje się na wszystkie 8. +Imiona pary trzymamy w jednej warstwie tekstowej (string typu "Martyna i Patryk"). + +Wymaga: uruchomiony Adobe Photoshop, pakiet photoshop-python-api. + +Użycie: + python buteleczki_slub_mloda_para.py --klient "Martyna Nowak" \\ + --imiona "Martyna i Patryk" --data "06.06.2026" + + python buteleczki_slub_mloda_para.py --klient "Martyna Nowak" \\ + --imiona "Martyna i Patryk" --data "06.06.2026" \\ + --podziekowanie "Dziękujemy za wspólną zabawę!" +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\ślub - buteleczki", + "Podziękowanie dla gości weselnych buteleczka z nadrukiem UV - Młoda para", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "szablon 370x300.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowując środek bounding boxa + (kompensacja dla wycentrowanych warstw).""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def open_smart_object_contents(app): + """Otwiera zawartość aktywnej warstwy Smart Object do edycji.""" + desc = ps.ActionDescriptor() + ref = ps.ActionReference() + ref.putEnumerated( + app.stringIDToTypeID("layer"), + app.stringIDToTypeID("ordinal"), + app.stringIDToTypeID("targetEnum"), + ) + desc.putReference(app.stringIDToTypeID("null"), ref) + app.executeAction(app.stringIDToTypeID("placedLayerEditContents"), desc) + + +def find_first_smart_object(doc): + for al in doc.artLayers: + if al.kind == 17: + return al + raise RuntimeError("Nie znaleziono warstwy Smart Object (kind=17) w szablonie") + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def generate(klient, imiona, data, podziekowanie=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + so_layer = find_first_smart_object(doc) + app.activeDocument.activeLayer = so_layer + open_smart_object_contents(app) + so_doc = app.activeDocument + print(f" Wszedłem do SO: {so_doc.name}") + + dane = so_doc.layerSets["dane"] + print(" Podmiana tekstów:") + set_layer_text(dane, "imiona", imiona) + set_layer_text(dane, "data", data) + set_layer_text(dane, "podziekowanie", podziekowanie) + + so_doc.save() + so_doc.close() + print(" SO zapisany") + + psd_opts = ps.PhotoshopSaveOptions() + app.activeDocument.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + app.activeDocument.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - buteleczki ślubne (Młoda para)" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego") + parser.add_argument("--imiona", required=True, help='Imiona pary (np. "Martyna i Patryk")') + parser.add_argument("--data", required=True, help="Data uroczystości (DD.MM.YYYY)") + parser.add_argument("--podziekowanie", default=None, help='Tekst podziękowania (opcjonalnie, domyślnie "Dziękujemy!")') + + args = parser.parse_args() + generate( + klient=args.klient, + imiona=args.imiona, + data=args.data, + podziekowanie=args.podziekowanie, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/email_photo_fetcher.py b/tools/generowanie/email_photo_fetcher.py new file mode 100644 index 0000000..8f25c88 --- /dev/null +++ b/tools/generowanie/email_photo_fetcher.py @@ -0,0 +1,179 @@ +""" +Pobieranie zdjec od klientow z poczty IMAP. + +Wspolny modul wykorzystywany przez generatory PSD ktore potrzebuja zdjecia +od klienta (np. akrylowe podziekowania). Lokalizuje maile od podanego adresu +nadawcy w ostatnich N dniach i pobiera pierwszy zalacznik graficzny. + +Wymagane zmienne srodowiskowe (.env w katalogu projektu): + EMAIL_01_HOST - host serwera (ten sam dla SMTP i IMAP) + EMAIL_01_USERNAME - login (adres email skrzynki) + EMAIL_01_PASSWORD - haslo + EMAIL_01_IMAP_PORT - opcjonalnie, domyslnie 993 (standard IMAP SSL) + EMAIL_01_IMAP_FOLDER - opcjonalnie, domyslnie INBOX + +Uzycie programowe: + from email_photo_fetcher import fetch_customer_photo + path = fetch_customer_photo("klient@example.com", "/tmp", days_back=60) + +Uzycie z CLI (do testow): + python email_photo_fetcher.py --email klient@example.com --out C:/tmp +""" + +import argparse +import email +import imaplib +import os +import re +import sys +from datetime import datetime, timedelta +from email.header import decode_header + + +IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".heic", ".webp", ".tif", ".tiff", ".bmp"} + + +def _project_root(): + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + + +def _load_env(): + """Lekka obsluga .env (KEY=VALUE), bez zaleznosci od python-dotenv.""" + env_path = os.path.join(_project_root(), ".env") + if not os.path.isfile(env_path): + return {} + out = {} + with open(env_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + k, _, v = line.partition("=") + v = v.strip().strip('"').strip("'") + out[k.strip()] = v + return out + + +def _imap_config(account_prefix="EMAIL_01"): + env = _load_env() + return { + "host": env.get(f"{account_prefix}_HOST"), + "port": int(env.get(f"{account_prefix}_IMAP_PORT", "993")), + "user": env.get(f"{account_prefix}_USERNAME"), + "password": env.get(f"{account_prefix}_PASSWORD"), + "folder": env.get(f"{account_prefix}_IMAP_FOLDER", "INBOX"), + } + + +def _decode_filename(raw_name): + if not raw_name: + return "" + parts = decode_header(raw_name) + out = [] + for chunk, enc in parts: + if isinstance(chunk, bytes): + try: + out.append(chunk.decode(enc or "utf-8", errors="replace")) + except LookupError: + out.append(chunk.decode("utf-8", errors="replace")) + else: + out.append(chunk) + return "".join(out) + + +def _safe_filename(name): + name = re.sub(r"[\\/:*?\"<>|]+", "_", name).strip() + return name or "attachment" + + +def _is_image(filename): + ext = os.path.splitext(filename)[1].lower() + return ext in IMAGE_EXTENSIONS + + +def fetch_customer_photo(customer_email, output_dir, days_back=60): + """Szuka maili od customer_email z ostatnich `days_back` dni i pobiera + pierwszy zalacznik graficzny do output_dir. Zwraca sciezke lub None.""" + cfg = _imap_config() + if not cfg["host"] or not cfg["user"] or not cfg["password"]: + raise RuntimeError( + "Brak konfiguracji konta w .env — wymagane: EMAIL_01_HOST, EMAIL_01_USERNAME, EMAIL_01_PASSWORD" + ) + + os.makedirs(output_dir, exist_ok=True) + + imap = imaplib.IMAP4_SSL(cfg["host"], cfg["port"]) + + try: + imap.login(cfg["user"], cfg["password"]) + imap.select(cfg["folder"]) + + since = (datetime.now() - timedelta(days=days_back)).strftime("%d-%b-%Y") + criteria = f'(FROM "{customer_email}" SINCE "{since}")' + status, data = imap.search(None, criteria) + if status != "OK" or not data or not data[0]: + return None + + ids = data[0].split() + # Iterujemy od najnowszego do najstarszego + for msg_id in reversed(ids): + status, msg_data = imap.fetch(msg_id, "(RFC822)") + if status != "OK" or not msg_data or not msg_data[0]: + continue + msg = email.message_from_bytes(msg_data[0][1]) + + for part in msg.walk(): + if part.get_content_maintype() == "multipart": + continue + disposition = str(part.get("Content-Disposition") or "") + filename = _decode_filename(part.get_filename()) + + if not filename: + continue + if "attachment" not in disposition.lower() and "inline" not in disposition.lower(): + continue + if not _is_image(filename): + continue + + payload = part.get_payload(decode=True) + if not payload: + continue + + safe = _safe_filename(filename) + stamp = datetime.now().strftime("%Y%m%d%H%M%S") + local_name = f"{customer_email}_{stamp}_{safe}" + local_path = os.path.join(output_dir, local_name) + with open(local_path, "wb") as f: + f.write(payload) + return local_path + + return None + finally: + try: + imap.logout() + except Exception: + pass + + +def main(): + parser = argparse.ArgumentParser(description="Pobierz zdjecie klienta z poczty IMAP") + parser.add_argument("--email", required=True, help="Adres email klienta (nadawca)") + parser.add_argument("--out", required=True, help="Katalog wyjsciowy dla zdjecia") + parser.add_argument("--days", type=int, default=60, help="Ile dni wstecz szukac (domyslnie 60)") + args = parser.parse_args() + + try: + path = fetch_customer_photo(args.email, args.out, days_back=args.days) + except Exception as exc: + print(f"BLAD: {exc}") + sys.exit(2) + + if path: + print(f"OK: {path}") + else: + print("BRAK: nie znaleziono zdjecia w mailach od tego klienta") + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py b/tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py new file mode 100644 index 0000000..0b48cbf --- /dev/null +++ b/tools/generowanie/pudelko_chrzest_dziewczynka_aniolek.py @@ -0,0 +1,121 @@ +""" +Generator PSD — Pudełko na pieniądze z życzeniami (Chrzest, dziewczynka, Aniołek). + +Makieta A3 — jedno pudełko, 6 ścianek (KL/KP + GL/GP + DL/DP). +Data jest w jednym miejscu: KP. DP nie ma daty (tylko imię i tytuł). + +Wymaga: uruchomiony Adobe Photoshop, pakiet photoshop-python-api. + +Użycie: + python pudelko_chrzest_dziewczynka_aniolek.py --klient "Anna Kowalska" \\ + --imie "Lenka" --data "19.04.2026" --od-kogo "Babcia Anna" +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Chrzest - Aniołek dziewczynka HDF UV", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowując środek bounding boxa + (kompensacja dla wycentrowanych warstw — patrz uwagi w innych skryptach).""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + # KP — data (jedno źródło prawdy dla daty w całym projekcie) + print(" [KP] data:") + set_layer_text(doc.layerSets["KP"], "data", data) + + # GL — życzenia (Layer 2 → dane) + print(" [GL] życzenia:") + gl_dane = doc.layerSets["GL"].layerSets["dane"] + set_layer_text(gl_dane, "od_kogo", od_kogo) + set_layer_text(gl_dane, "naglowek", naglowek) + set_layer_text(gl_dane, "zyczenia", zyczenia) + + # GP — imię + tytuł (Layer 1 kopia → dane); brak daty na ściance + print(" [GP] imię/tytuł:") + gp_dane = doc.layerSets["GP"].layerSets["dane"] + set_layer_text(gp_dane, "imie", imie) + set_layer_text(gp_dane, "tytul", tytul) + + # DL — życzenia (warstwy bezpośrednio w secie) + print(" [DL] życzenia:") + dl = doc.layerSets["DL"] + set_layer_text(dl, "od_kogo", od_kogo) + set_layer_text(dl, "naglowek", naglowek) + set_layer_text(dl, "zyczenia", zyczenia) + + # DP — imię + tytuł; brak daty na ściance + print(" [DP] imię/tytuł:") + dp = doc.layerSets["DP"] + set_layer_text(dp, "imie", imie) + set_layer_text(dp, "tytul", tytul) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser( + description="Generator PSD - pudełko na pieniądze (Chrzest, dziewczynka Aniołek)" + ) + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego") + parser.add_argument("--imie", required=True, help="Odmienione imię dziecka") + parser.add_argument("--data", required=True, help="Data uroczystości (DD.MM.YYYY)") + parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Kto składa życzenia") + parser.add_argument("--zyczenia", default=None, help="Treść życzeń (opcjonalnie, domyślnie z szablonu)") + parser.add_argument("--naglowek", default=None, help="Nagłówek życzeń (opcjonalnie, domyślnie z szablonu)") + parser.add_argument("--tytul", default=None, help="Tytuł (opcjonalnie, domyślnie z szablonu)") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_chrzest_golabek_hdf.py b/tools/generowanie/pudelko_chrzest_golabek_hdf.py new file mode 100644 index 0000000..1ad8ce1 --- /dev/null +++ b/tools/generowanie/pudelko_chrzest_golabek_hdf.py @@ -0,0 +1,98 @@ +""" +Generator PSD - Pudelko na pieniadze z zyczeniami na Chrzest (Gołąbek HDF UV). + +Makieta A3 z panelami: +- DL: od_kogo, naglowek, zyczenia +- DP: imie, data, tytul + +Teksty sa bezposrednio w grupach DL/DP. Brak Smart Objectow. +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Chrzest - Gołąbek HDF UV", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowujac srodek bounding boxa.""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + dl = doc.layerSets["DL"] + print(" [DL] zyczenia:") + set_layer_text(dl, "od_kogo", od_kogo) + set_layer_text(dl, "naglowek", naglowek) + set_layer_text(dl, "zyczenia", zyczenia) + + dp = doc.layerSets["DP"] + print(" [DP] imie/data/tytul:") + set_layer_text(dp, "imie", imie) + set_layer_text(dp, "data", data) + set_layer_text(dp, "tytul", tytul) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser(description="Generator PSD - Pudelko chrzest, Golabek HDF UV") + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Gabrysi)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)") + parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)") + parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Pamiątka Chrztu Świętego')") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_chrzest_golabek_uv.py b/tools/generowanie/pudelko_chrzest_golabek_uv.py new file mode 100644 index 0000000..ec44023 --- /dev/null +++ b/tools/generowanie/pudelko_chrzest_golabek_uv.py @@ -0,0 +1,98 @@ +""" +Generator PSD - Pudelko na pieniadze z zyczeniami na Chrzest (Gołąbek UV). + +Makieta A3 z panelami: +- DL: od_kogo, naglowek, zyczenia +- DP: imie, data, tytul + +Teksty sa bezposrednio w grupach DL/DP. Brak Smart Objectow. +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Chrzest - Gołąbek UV", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowujac srodek bounding boxa.""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + dl = doc.layerSets["DL"] + print(" [DL] zyczenia:") + set_layer_text(dl, "od_kogo", od_kogo) + set_layer_text(dl, "naglowek", naglowek) + set_layer_text(dl, "zyczenia", zyczenia) + + dp = doc.layerSets["DP"] + print(" [DP] imie/data/tytul:") + set_layer_text(dp, "imie", imie) + set_layer_text(dp, "data", data) + set_layer_text(dp, "tytul", tytul) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser(description="Generator PSD - Pudelko chrzest, Golabek UV") + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Gabrysi)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)") + parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)") + parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Pamiątka Chrztu Świętego')") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_komunia_chlopiec.py b/tools/generowanie/pudelko_komunia_chlopiec.py new file mode 100644 index 0000000..f3e31cd --- /dev/null +++ b/tools/generowanie/pudelko_komunia_chlopiec.py @@ -0,0 +1,36 @@ +""" +Generator PSD — Pudełko na pieniądze (Komunia, chłopiec). + +Cienki wrapper na _pudelko_komunia_core — tylko ścieżka do szablonu. +""" + +import os +from _pudelko_komunia_core import build_arg_parser, generate + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Chłopiec", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def main(): + parser = build_arg_parser("Generator PSD - pudełko na pieniądze (Komunia, chłopiec)") + args = parser.parse_args() + generate( + szablon_path=SZABLON_PATH, + gotowe_dir=GOTOWE_DIR, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + klient=args.klient, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_komunia_dziewczynka.py b/tools/generowanie/pudelko_komunia_dziewczynka.py new file mode 100644 index 0000000..06335fa --- /dev/null +++ b/tools/generowanie/pudelko_komunia_dziewczynka.py @@ -0,0 +1,36 @@ +""" +Generator PSD — Pudełko na pieniądze (Komunia, dziewczynka). + +Cienki wrapper na _pudelko_komunia_core — tylko ścieżka do szablonu. +""" + +import os +from _pudelko_komunia_core import build_arg_parser, generate + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Dziewczynka", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def main(): + parser = build_arg_parser("Generator PSD - pudełko na pieniądze (Komunia, dziewczynka)") + args = parser.parse_args() + generate( + szablon_path=SZABLON_PATH, + gotowe_dir=GOTOWE_DIR, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + klient=args.klient, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main() diff --git a/tools/generowanie/pudelko_komunia_kwiaty.py b/tools/generowanie/pudelko_komunia_kwiaty.py new file mode 100644 index 0000000..1e47690 --- /dev/null +++ b/tools/generowanie/pudelko_komunia_kwiaty.py @@ -0,0 +1,98 @@ +""" +Generator PSD - Pudelko na pieniadze z zyczeniami (Komunia, wzor Kwiaty). + +Makieta A3 z 6 panelami, ale tylko DL i DP sa uzywane: +- DL: imie, data, tytul +- DP: od_kogo, naglowek, zyczenia + +Teksty sa bezposrednio w grupach DL/DP (brak subgrupy "dane"). Brak Smart Objectow. +Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api. +""" + +import argparse +import os +import photoshop.api as ps + + +PROJEKT_DIR = os.path.join( + r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze", + "Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Kwiaty", +) +SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3.psd") +GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") + + +def set_text(layer, new_text): + """Zmienia tekst warstwy zachowujac srodek bounding boxa.""" + b = [float(x) for x in layer.bounds] + cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2 + layer.textItem.contents = new_text + b2 = [float(x) for x in layer.bounds] + cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2 + dx, dy = cx - cx2, cy - cy2 + if dx or dy: + layer.translate(dx, dy) + + +def set_layer_text(container, layer_name, new_text): + if new_text is None: + return + layer = container.artLayers[layer_name] + old = layer.textItem.contents + set_text(layer, new_text) + print(f' {layer_name}: "{old}" -> "{new_text}"') + + +def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None): + os.makedirs(GOTOWE_DIR, exist_ok=True) + output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") + + app = ps.Application() + doc = app.open(SZABLON_PATH) + print(f"Otwarto szablon: {doc.name}") + + dl = doc.layerSets["DL"] + print(" [DL] imie/data/tytul:") + set_layer_text(dl, "imie", imie) + set_layer_text(dl, "data", data) + set_layer_text(dl, "tytul", tytul) + + dp = doc.layerSets["DP"] + print(" [DP] zyczenia:") + set_layer_text(dp, "od_kogo", od_kogo) + set_layer_text(dp, "naglowek", naglowek) + set_layer_text(dp, "zyczenia", zyczenia) + + psd_opts = ps.PhotoshopSaveOptions() + doc.saveAs(output_path, psd_opts, True) + print(f"Zapisano: {output_path}") + + doc.close(ps.SaveOptions.DoNotSaveChanges) + print("Gotowe!") + return output_path + + +def main(): + parser = argparse.ArgumentParser(description="Generator PSD - Pudelko komunia, wzor Kwiaty") + parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego") + parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Karolinki)") + parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)") + parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Ciocia i Wujek)") + parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)") + parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie z szablonu)") + + args = parser.parse_args() + generate( + klient=args.klient, + imie=args.imie, + data=args.data, + od_kogo=args.od_kogo, + zyczenia=args.zyczenia, + naglowek=args.naglowek, + tytul=args.tytul, + ) + + +if __name__ == "__main__": + main()