This commit is contained in:
2026-04-12 21:43:39 +02:00
parent 63bd1e73f2
commit f72a5019e9
27 changed files with 1791 additions and 266 deletions

View File

@@ -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

10
.env
View File

@@ -24,4 +24,12 @@ pracownia.key=9554daf4bbcbbb5e72a2b48ee7d6a7f20262713d72484b781460e2c772d813fc
ALLEGRO_USER_AGENT_URL=https://orderpro.pl/info
login=jacek.pyziak@project-pro.pl
password=ProjectPro2025!
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

View File

@@ -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<64>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<64>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<64>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"}

View File

@@ -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
}
}
}
}
},

View File

@@ -0,0 +1,2 @@
ALTER TABLE project_mappings
ADD COLUMN IF NOT EXISTS requires_photo TINYINT(1) NOT NULL DEFAULT 0 AFTER output_dir;

View File

@@ -1135,6 +1135,7 @@ return [
'pattern' => 'Wzorzec nazwy produktu',
'script' => 'Skrypt generujacy',
'output_dir' => 'Katalog wyjsciowy',
'requires_photo' => 'Wymaga zdjecia',
'active' => 'Status',
'actions' => 'Akcje',
],

View File

@@ -41,6 +41,14 @@ $scripts = is_array($scripts ?? null) ? $scripts : [];
<input class="form-control" type="text" name="output_dir" placeholder="<?= $e($t('settings.project_mapping.placeholders.output_dir')) ?>">
</label>
<label class="form-field pm-form__field pm-form__field--check">
<span class="field-label">&nbsp;</span>
<span class="checkbox-row">
<input type="checkbox" name="requires_photo" value="1">
<?= $e($t('settings.project_mapping.fields.requires_photo')) ?>
</span>
</label>
<div class="pm-form__actions">
<button type="submit" class="btn btn--action"><?= $e($t('settings.project_mapping.actions.add')) ?></button>
</div>
@@ -60,6 +68,7 @@ $scripts = is_array($scripts ?? null) ? $scripts : [];
<th><?= $e($t('settings.project_mapping.fields.pattern')) ?></th>
<th><?= $e($t('settings.project_mapping.fields.script')) ?></th>
<th><?= $e($t('settings.project_mapping.fields.output_dir')) ?></th>
<th class="text-center"><?= $e($t('settings.project_mapping.fields.requires_photo')) ?></th>
<th class="text-center"><?= $e($t('settings.project_mapping.fields.active')) ?></th>
<th class="text-center"><?= $e($t('settings.project_mapping.fields.actions')) ?></th>
</tr>
@@ -70,6 +79,7 @@ $scripts = is_array($scripts ?? null) ? $scripts : [];
<td class="pm-row__pattern"><?= $e((string) $mapping['product_name_pattern']) ?></td>
<td class="pm-row__script"><?= $e((string) $mapping['script_name']) ?></td>
<td class="pm-row__dir"><?= $e((string) ($mapping['output_dir'] ?? '-')) ?></td>
<td class="text-center"><?= !empty($mapping['requires_photo']) ? '✓' : '' ?></td>
<td class="text-center">
<form action="/settings/project-mappings/<?= (int) $mapping['id'] ?>/toggle" method="post" class="inline-form">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
@@ -83,7 +93,8 @@ $scripts = is_array($scripts ?? null) ? $scripts : [];
data-id="<?= (int) $mapping['id'] ?>"
data-pattern="<?= $e((string) $mapping['product_name_pattern']) ?>"
data-script="<?= $e((string) $mapping['script_name']) ?>"
data-output-dir="<?= $e((string) ($mapping['output_dir'] ?? '')) ?>">
data-output-dir="<?= $e((string) ($mapping['output_dir'] ?? '')) ?>"
data-requires-photo="<?= !empty($mapping['requires_photo']) ? '1' : '0' ?>">
<?= $e($t('settings.project_mapping.actions.edit')) ?>
</button>
<button type="button" class="btn btn--sm btn--danger js-pm-delete"
@@ -126,6 +137,13 @@ $scripts = is_array($scripts ?? null) ? $scripts : [];
<input class="form-control" type="text" name="output_dir">
</label>
<label class="form-field mt-8">
<span class="checkbox-row">
<input type="checkbox" name="requires_photo" value="1">
<?= $e($t('settings.project_mapping.fields.requires_photo')) ?>
</span>
</label>
<div class="mt-12">
<button type="submit" class="btn btn--action"><?= $e($t('settings.project_mapping.actions.save')) ?></button>
<button type="button" class="btn btn--outline js-pm-modal-close"><?= $e($t('settings.project_mapping.actions.cancel')) ?></button>
@@ -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('<?= $e($t('settings.project_mapping.confirm_delete')) ?>', 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: '<?= $e($t('settings.project_mapping.actions.delete')) ?>',
message: '<?= $e($t('settings.project_mapping.confirm_delete')) ?>',
danger: true
}).then(function(confirmed) {
if (confirmed) submitDelete(id, token);
});
});
});
});

View File

@@ -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'));

View File

@@ -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,
]);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 MiB

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()