feat: aspektarian, deklinacja i antyscja trafiają do raportu i PDF-a
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m13s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m49s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 29s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 20s
build-render / build (push) Successful in 44s
build / build (push) Successful in 54s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m19s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m59s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 34s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m13s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m49s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 29s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 20s
build-render / build (push) Successful in 44s
build / build (push) Successful in 54s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m19s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m59s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 34s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Zasada: co składamy, dodajemy i wyświetlamy, MA trafiać do finalnego raportu
(«Skompiluj») i do PDF-a — nie tylko na stronę /chart. Do tej pory do raportu i
druku szło samo koło; aspektarian (etap 5) i deklinacja/antyscja (etap 6) były
tylko w podglądzie horoskopu.
RAPORT «Skompiluj» (podgląd): handler /compile liczy teraz wszystkie cztery
rysunki, a szablon je pokazuje (koło, aspektarian, deklinacja, antyscja).
PDF (usługa render) — uogólnienie z jednego rysunku na LISTĘ:
- Kontrakt raportu: `figures = [{svg, caption}]` (uporządkowana). `wheel_svg`
zostaje dla zgodności wstecznej jako pojedynczy rysunek.
- `compile.py`: każdy SVG osobno przez rsvg-convert → PDF (fig0…figN); braki/
błędy pomijane (rysunek nie może wywalić raportu, tekst ważniejszy).
- `latex.py build()`: rysunki w sekcji 3 (po danych, przed natalną) w PODANEJ
kolejności, każdy z podpisem. Jedna reguła składania: keepaspectratio z limitem
szerokości i wysokości — kwadratowe (koło, aspektarian) ogranicza wysokość,
szerokie (deklinacja, antyscja) szerokość, bez zniekształceń.
- `compile_pdf` (prezentacja): renderuje komplet w motywie DRUKU i wysyła jako
`figures`.
Testy: render +5 (kolejność, podpisy, zgodność wsteczna, pomijanie pustych),
prezentacja +3 (raport pokazuje komplet, PDF składa komplet). Render 32,
prezentacja 173.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #41.
This commit is contained in:
@@ -147,6 +147,8 @@ def compile_build(
|
||||
from app import chartwheel
|
||||
ctx["wheel_svg"] = chartwheel.render(ctx["result"])
|
||||
ctx["aspectarian_svg"] = chartwheel.render_aspectarian(ctx["result"]) # PRE-18
|
||||
ctx["declination_svg"] = chartwheel.render_declination(ctx["result"]) # LOG-07 (etap 6)
|
||||
ctx["antiscia_svg"] = chartwheel.render_antiscia(ctx["result"]) # LOG-07 (etap 6)
|
||||
except (httpx.HTTPError,) as e:
|
||||
ctx["error"] = _logic_error(e)
|
||||
except ValueError as e:
|
||||
@@ -178,7 +180,7 @@ def compile_pdf(payload: dict):
|
||||
except (ValueError, TypeError) as e:
|
||||
return JSONResponse({"detail": f"Niepoprawne dane wejściowe: {e}"}, status_code=422)
|
||||
|
||||
wheel_svg = ""
|
||||
figures: list[dict] = []
|
||||
try:
|
||||
chart = logic.positions(
|
||||
when_utc_iso=iso_utc,
|
||||
@@ -188,17 +190,25 @@ def compile_pdf(payload: dict):
|
||||
)
|
||||
from app import chartwheel
|
||||
|
||||
wheel_svg = chartwheel.render(chart, theme="print")
|
||||
# Zasada: co pokazujemy na stronie, ma trafić do PDF-a. Wszystkie rysunki
|
||||
# w motywie DRUKU — samodzielny konwerter SVG→PDF nie zna arkusza, więc
|
||||
# zmienne CSS i font glifów muszą być wprost w rysunku.
|
||||
for svg, caption in (
|
||||
(chartwheel.render(chart, theme="print"), "Kosmogram"),
|
||||
(chartwheel.render_aspectarian(chart, theme="print"), "Aspektarian — siatka aspektów"),
|
||||
(chartwheel.render_declination(chart, theme="print"), "Wykres deklinacji"),
|
||||
(chartwheel.render_antiscia(chart, theme="print"), "Oś antyscji"),
|
||||
):
|
||||
if svg:
|
||||
figures.append({"svg": svg, "caption": caption})
|
||||
except httpx.HTTPError as e:
|
||||
# Brak rysunku nie może zablokować raportu — tekst jest ważniejszy.
|
||||
log_note = _logic_error(e)
|
||||
chart, wheel_svg = None, ""
|
||||
data = {**data, "wheel_error": log_note}
|
||||
# Brak rysunków nie może zablokować raportu — tekst jest ważniejszy.
|
||||
data = {**data, "wheel_error": _logic_error(e)}
|
||||
|
||||
report = {
|
||||
"person": payload.get("person") or "",
|
||||
"data": {**data, "moment_utc": label},
|
||||
"wheel_svg": wheel_svg,
|
||||
"figures": figures,
|
||||
"natal": payload.get("natal") or {},
|
||||
"predictions": payload.get("predictions") or [],
|
||||
}
|
||||
|
||||
@@ -91,6 +91,20 @@ zapamiętane predykcje okresowe. Dane pobiera z pozostałych zakładek — nie t
|
||||
</figure>
|
||||
{% endif %}
|
||||
|
||||
{% if declination_svg %}
|
||||
<figure class="declination-fig">
|
||||
{{ declination_svg | safe }}
|
||||
<figcaption class="muted small">Wykres deklinacji — paralele i out-of-bounds (LOG-07).</figcaption>
|
||||
</figure>
|
||||
{% endif %}
|
||||
|
||||
{% if antiscia_svg %}
|
||||
<figure class="antiscia-fig">
|
||||
{{ antiscia_svg | safe }}
|
||||
<figcaption class="muted small">Oś antyscji — odbicia względem przesileń i równonocy (LOG-07).</figcaption>
|
||||
</figure>
|
||||
{% endif %}
|
||||
|
||||
{# ── 3. Dane policzone ────────────────────────────────────────────── #}
|
||||
<div class="meta">Horoskop · silnik {{ result.engine }}
|
||||
{% if result.house_system %}· domy {{ result.house_system }}{% endif %}
|
||||
|
||||
@@ -61,6 +61,33 @@ def test_person_name_heads_the_report():
|
||||
assert "form.person" in TPL
|
||||
|
||||
|
||||
# ───── wszystkie rysunki w raporcie i w PDF (nie tylko koło) ─────
|
||||
# Zasada: co pokazujemy na stronie, ma trafić do podsumowania i do PDF-a.
|
||||
|
||||
def test_report_shows_every_chart_figure():
|
||||
"""Raport «Skompiluj» pokazuje wszystkie rysunki, nie tylko koło."""
|
||||
for cls in ("wheel-fig", "aspectarian-fig", "declination-fig", "antiscia-fig"):
|
||||
assert cls in TPL, f"brak {cls} w raporcie"
|
||||
|
||||
|
||||
def test_compile_page_renders_all_figures():
|
||||
"""Handler /compile liczy wszystkie rysunki do podglądu raportu."""
|
||||
for var in ("aspectarian_svg", "declination_svg", "antiscia_svg"):
|
||||
assert var in MAIN, f"/compile nie ustawia {var}"
|
||||
|
||||
|
||||
def test_pdf_bundles_all_figures_in_print_theme():
|
||||
"""compile_pdf składa KOMPLET rysunków (motyw druku) i wysyła jako `figures`."""
|
||||
assert '"figures": figures' in MAIN
|
||||
for call in (
|
||||
'render(chart, theme="print")',
|
||||
'render_aspectarian(chart, theme="print")',
|
||||
'render_declination(chart, theme="print")',
|
||||
'render_antiscia(chart, theme="print")',
|
||||
):
|
||||
assert call in MAIN, f"PDF nie składa: {call}"
|
||||
|
||||
|
||||
# ──────────────────────── zbieranie materiału z magazynów ────────────────
|
||||
|
||||
def test_reads_stores_through_their_api_not_raw_storage():
|
||||
|
||||
@@ -123,10 +123,10 @@ def test_pdf_button_exists():
|
||||
|
||||
|
||||
def test_wheel_failure_does_not_block_the_report():
|
||||
"""Brak rysunku ma dać raport bez kosmogramu, a nie brak raportu — tekst
|
||||
kosztował wywołanie modelu, rysunek policzymy zawsze."""
|
||||
assert "wheel_svg = \"\"" in MAIN or 'wheel_svg, = ""' in MAIN
|
||||
assert "Brak rysunku nie może zablokować raportu" in MAIN
|
||||
"""Brak rysunków ma dać raport bez nich, a nie brak raportu — tekst kosztował
|
||||
wywołanie modelu, rysunki policzymy zawsze."""
|
||||
assert "figures: list[dict] = []" in MAIN
|
||||
assert "Brak rysunków nie może zablokować raportu" in MAIN
|
||||
|
||||
|
||||
# ─────────────────────────────────── pomocnicze ──────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user